001: /*
002: * This is free software, licensed under the Gnu Public License (GPL)
003: * get a copy from <http://www.gnu.org/licenses/gpl.html>
004: * @version $Id: SQLMetaDataBuilder.java,v 1.7 2005/06/18 04:58:13 hzeller Exp $
005: * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a>
006: */
007: package henplus;
008:
009: import henplus.sqlmodel.Column;
010: import henplus.sqlmodel.ColumnFkInfo;
011: import henplus.sqlmodel.PrimaryKey;
012: import henplus.sqlmodel.Table;
013:
014: import java.sql.DatabaseMetaData;
015: import java.sql.ResultSet;
016: import java.sql.SQLException;
017: import java.util.ArrayList;
018: import java.util.Collection;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.NoSuchElementException;
024:
025: public final class SQLMetaDataBuilder {
026: final private static String[] LIST_TABLES = { "TABLE" };
027: private static final boolean _verbose = false;
028:
029: // column description
030: public static final int TABLE_NAME = 3; // String
031: public static final int COLUMN_NAME = 4; // String
032: public static final int DATA_TYPE = 5; // int -> java.sql.Types
033: public static final int TYPE_NAME = 6; // String
034: public static final int COLUMN_SIZE = 7; // int
035: public static final int NULLABLE = 11; // int:
036: public static final int COLUMN_DEF = 13; // String
037: public static final int ORDINAL_POSITION = 17; // int, starting at 1
038: /*
039: * columnNoNulls - might not allow NULL values
040: * columnNullable - definitely allows NULL values
041: * columnNullableUnknown - nullability unknown
042: */
043: public static final int IS_NULLABLE = 17;
044:
045: // primary key description
046: public static final int PK_DESC_COLUMN_NAME = 4;
047: public static final int PK_DESC_KEY_SEQ = 5;
048: public static final int PK_DESC_PK_NAME = 6;
049:
050: // foreign key description
051: private static final int FK_PKTABLE_NAME = 3;
052: private static final int FK_PKCOLUMN_NAME = 4;
053: private static final int FK_FKCOLUMN_NAME = 8;
054: private static final int FK_FK_NAME = 12;
055:
056: private boolean _interrupted;
057:
058: /* (non-Javadoc)
059: * @see henplus.Interruptable#interrupt()
060: */
061: public void interrupt() {
062: _interrupted = true;
063: }
064:
065: public SQLMetaData getMetaData(SQLSession session) {
066: ResultSet rset = null;
067: List tableList = new ArrayList();
068: try {
069: DatabaseMetaData meta = session.getConnection()
070: .getMetaData();
071: rset = meta.getTables(null, null, null, LIST_TABLES);
072: while (rset.next()) {
073: tableList.add(rset.getString(3));
074: }
075: } catch (Exception e) {
076: // ignore.
077: } finally {
078: if (rset != null) {
079: try {
080: rset.close();
081: } catch (Exception e) {
082: }
083: }
084: }
085: return getMetaData(session, tableList);
086: }
087:
088: public SQLMetaData getMetaData(SQLSession session,
089: Collection /*<String>*/tableNames) {
090: return getMetaData(session, tableNames.iterator());
091: }
092:
093: public SQLMetaData getMetaData(SQLSession session,
094: final Iterator /*<String>*/tableNamesIter) {
095: SQLMetaData result = new SQLMetaData();
096:
097: ResultSet rset = null;
098: try {
099: _interrupted = false;
100: String catalog = session.getConnection().getCatalog();
101:
102: if (_interrupted)
103: return null;
104:
105: DatabaseMetaData meta = session.getConnection()
106: .getMetaData();
107:
108: while (tableNamesIter.hasNext() && !_interrupted) {
109: String tableName = (String) tableNamesIter.next();
110: rset = meta.getColumns(catalog, null, tableName, null);
111: Table table = buildTable(catalog, meta, tableName, rset);
112: result.addTable(table);
113: }
114: } catch (Exception e) {
115: if (_verbose)
116: e.printStackTrace();
117: HenPlus.msg().println(
118: "Database problem reading meta data: "
119: + e.getMessage().trim());
120: } finally {
121: if (rset != null) {
122: try {
123: rset.close();
124: } catch (Exception e) {
125: }
126: }
127: }
128:
129: return result;
130: }
131:
132: public Table getTable(SQLSession session, String tableName) {
133: Table table = null;
134: ResultSet rset = null;
135: try {
136: String catalog = session.getConnection().getCatalog();
137: DatabaseMetaData meta = session.getConnection()
138: .getMetaData();
139: rset = meta.getColumns(catalog, null, tableName, null);
140: table = buildTable(catalog, meta, tableName, rset);
141: } catch (Exception e) {
142: if (_verbose)
143: e.printStackTrace();
144: HenPlus.msg().println(
145: "Database problem reading meta data: "
146: + e.getMessage().trim());
147: } finally {
148: if (rset != null) {
149: try {
150: rset.close();
151: } catch (Exception e) {
152: }
153: }
154: }
155: return table;
156: }
157:
158: private Table buildTable(String catalog, DatabaseMetaData meta,
159: String tableName, ResultSet rset) throws SQLException {
160:
161: Table table = null;
162: if (rset != null) {
163: table = new Table(tableName);
164: PrimaryKey pk = getPrimaryKey(meta, tableName);
165: Map fks = getForeignKeys(meta, tableName);
166: // what about the following duplicate?
167: // rset = meta.getColumns(catalog, null, tableName, null);
168: while (!_interrupted && rset.next()) {
169: String colname = rset.getString(COLUMN_NAME);
170: Column column = new Column(colname);
171: column.setType(rset.getString(TYPE_NAME));
172: column.setSize(rset.getInt(COLUMN_SIZE));
173: boolean nullable = (rset.getInt(NULLABLE) == DatabaseMetaData.columnNullable) ? true
174: : false;
175: column.setNullable(nullable);
176: String defaultVal = rset.getString(COLUMN_DEF);
177: column.setDefault((defaultVal != null) ? defaultVal
178: .trim() : null);
179: column.setPosition(rset.getInt(ORDINAL_POSITION));
180: column.setPkInfo(pk.getColumnPkInfo(colname));
181: column.setFkInfo((ColumnFkInfo) fks.get(colname));
182:
183: table.addColumn(column);
184: }
185: rset.close();
186: }
187: return table;
188: }
189:
190: private PrimaryKey getPrimaryKey(DatabaseMetaData meta,
191: String tabName) throws SQLException {
192: PrimaryKey result = null;
193: ResultSet rset = meta.getPrimaryKeys(null, null, tabName);
194: if (rset != null) {
195: result = new PrimaryKey();
196: String pkname = null;
197: while (rset.next()) {
198: String col = rset.getString(PK_DESC_COLUMN_NAME);
199: pkname = rset.getString(PK_DESC_PK_NAME);
200: int pkseq = rset.getInt(PK_DESC_KEY_SEQ);
201: result.addColumn(col, pkname, pkseq);
202: }
203: rset.close();
204: }
205: return result;
206: }
207:
208: private Map getForeignKeys(DatabaseMetaData meta, String tabName)
209: throws SQLException {
210: Map fks = new HashMap();
211:
212: ResultSet rset = null;
213: // some jdbc version 2 drivers (connector/j) have problems with foreign keys...
214: try {
215: rset = meta.getImportedKeys(null, null, tabName);
216: } catch (NoSuchElementException e) {
217: if (_verbose)
218: HenPlus.msg().println(
219: "Database problem reading meta data: " + e);
220: }
221:
222: if (rset != null) {
223: while (rset.next()) {
224: ColumnFkInfo fk = new ColumnFkInfo(rset
225: .getString(FK_FK_NAME), rset
226: .getString(FK_PKTABLE_NAME), rset
227: .getString(FK_PKCOLUMN_NAME));
228: String col = rset.getString(FK_FKCOLUMN_NAME);
229: fks.put(col, fk);
230: }
231: rset.close();
232: }
233: return fks;
234: }
235:
236: }
|