001: /*
002: ** $Id: SchemaColumnModel.java,v 1.14 2000/10/26 08:34:15 mrw Exp $
003: **
004: ** Mike Wilson, September 2000, mrw@whisperingwind.co.uk
005: **
006: ** (C) Copyright 2000, Mike Wilson, Reading, Berkshire, UK
007: **
008: ** This program is free software; you can redistribute it and/or modify
009: ** it under the terms of the GNU General Public License as published by
010: ** the Free Software Foundation; either version 2 of the License, or
011: ** (at your option) any later version.
012: **
013: ** This program is distributed in the hope that it will be useful,
014: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
015: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: ** GNU General Public License for more details.
017: **
018: ** You should have received a copy of the GNU Library General
019: ** Public License along with this library; if not, write to the
020: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
021: ** Boston, MA 02111-1307 USA.
022: */
023:
024: package uk.co.whisperingwind.vienna;
025:
026: import java.sql.Connection;
027: import java.sql.DatabaseMetaData;
028: import java.sql.ResultSet;
029: import java.sql.ResultSetMetaData;
030: import java.sql.SQLException;
031: import java.sql.Statement;
032: import java.util.HashMap;
033: import java.util.Vector;
034: import javax.swing.table.TableModel;
035: import uk.co.whisperingwind.framework.Dialogs;
036: import uk.co.whisperingwind.framework.Model;
037: import uk.co.whisperingwind.framework.ExceptionDialog;
038: import uk.co.whisperingwind.framework.VectorTableModel;
039: import uk.co.whisperingwind.framework.SwingThread;
040:
041: /**
042: ** Column Model for the Schema View. Maintains a list of column names,
043: ** types, sizes etc.
044: */
045:
046: class SchemaColumnModel extends Model {
047: private Connection connection = null;
048: private String schemaName = null;
049: private String loadedTable = null;
050: private HashMap typeMap = null;
051: private ColumnLoader columnLoader = null;
052: private VectorTableModel columnModel = new VectorTableModel();
053:
054: public SchemaColumnModel(Connection theConnection,
055: String theSchemaName) {
056: connection = theConnection;
057: schemaName = theSchemaName;
058:
059: columnModel.addName("Name", 32);
060: columnModel.addName("Type", 32);
061: columnModel.addName("Nullable", 32);
062: }
063:
064: public TableModel getTableModel() {
065: return columnModel;
066: }
067:
068: public void clear() {
069: columnModel.clear();
070: }
071:
072: /**
073: ** Load the column details for the specified table. Runs in a
074: ** separate thread so the GUI remains alive.
075: **
076: ** If a "Load columns" thread is already running, stop it and wait
077: ** for it to complete before starting another.
078: */
079:
080: public boolean load(String tableName, String tableType) {
081: boolean started = false;
082:
083: if (tableName != null && !tableName.equals(loadedTable)) {
084: if (columnLoader != null)
085: columnLoader.interrupt();
086:
087: loadedTable = new String(tableName);
088: columnLoader = new ColumnLoader(tableName, tableType);
089: columnLoader.start();
090: started = true;
091: }
092:
093: return started;
094: }
095:
096: /**
097: ** Worker to load the column details. Can be interrupted (sort of)
098: ** by calling stopLoad ().
099: */
100:
101: private class ColumnLoader extends SwingThread {
102: private String tableName = null;
103: private String tableType = null;
104: private VectorTableModel newColumnModel = new VectorTableModel();
105:
106: public ColumnLoader(String name, String type) {
107: newColumnModel.addName("Name", 32);
108: newColumnModel.addName("Type", 32);
109: newColumnModel.addName("Nullable", 32);
110:
111: tableName = name;
112: tableType = type;
113: }
114:
115: public void construct() {
116: try {
117: if (typeMap == null)
118: loadTypes();
119:
120: if (tableType.equals("TABLE")
121: || tableType.equals("VIEW"))
122: loadTable();
123: else if (tableType.equals("SYNONYM"))
124: loadSynonym();
125: } catch (SQLException ex) {
126: new ExceptionDialog(ex);
127: }
128: }
129:
130: private void loadTable() {
131: try {
132: DatabaseMetaData metaData = connection.getMetaData();
133: ResultSet columnSet = metaData.getColumns(null,
134: schemaName, loadedTable, "%");
135:
136: while (columnSet.next() && !stopped) {
137: String name = columnSet.getString("COLUMN_NAME");
138: Integer type = new Integer(columnSet
139: .getInt("DATA_TYPE"));
140: String size = columnSet.getString("COLUMN_SIZE");
141: String nullable = columnSet
142: .getString("IS_NULLABLE");
143:
144: String description = type.toString();
145:
146: if (typeMap.containsKey(type)) {
147: description = (String) typeMap.get(type);
148: description = description;
149:
150: if (size.length() > 0 && !size.equals("0"))
151: description = description + " (" + size
152: + ")";
153: }
154:
155: Vector row = newColumnModel.addRow();
156: row.add(name);
157: row.add(description);
158: row.add(nullable);
159: }
160: } catch (SQLException ex) {
161: new ExceptionDialog(ex);
162: }
163: }
164:
165: private void loadSynonym() {
166: try {
167: Statement statement = connection.createStatement();
168: String sql = "select * from " + tableName
169: + " where 1 = 2";
170: ResultSet resultSet = statement.executeQuery(sql);
171: ResultSetMetaData columnSet = resultSet.getMetaData();
172:
173: for (int i = 1; i <= columnSet.getColumnCount()
174: && !stopped; i++) {
175: String name = columnSet.getColumnName(i);
176: Integer type = new Integer(columnSet
177: .getColumnType(i));
178: int precision = columnSet.getPrecision(i);
179: int scale = columnSet.getScale(i);
180: int size = columnSet.getColumnDisplaySize(i);
181: String nullable = "Unknown";
182:
183: if (columnSet.isNullable(i) == 1) {
184: //System.out.println (columnSet.isNullable (i));
185: } else {
186: }
187:
188: String description = type.toString();
189:
190: if (typeMap.containsKey(type)) {
191: description = (String) typeMap.get(type);
192:
193: if (precision > 0 || scale > 0) {
194: if (scale > 0) {
195: description = description + " ("
196: + precision + "." + scale + ")";
197: } else {
198: description = description + " ("
199: + precision + ")";
200: }
201: } else {
202: if (size > 0)
203: description = description + " (" + size
204: + ")";
205: }
206: }
207:
208: Vector row = newColumnModel.addRow();
209: row.add(name);
210: row.add(description);
211: row.add(nullable);
212: }
213: } catch (SQLException ex) {
214: Dialogs
215: .showError(
216: "Columns unavailable",
217: "Cannot get columns for "
218: + tableName
219: + ". Perhaps this synonym is not a table.");
220: }
221: }
222:
223: private void loadTypes() throws SQLException {
224: typeMap = new HashMap();
225: DatabaseMetaData metaData = connection.getMetaData();
226: ResultSet types = metaData.getTypeInfo();
227:
228: while (types.next()) {
229: Integer type = new Integer(types.getInt("DATA_TYPE"));
230: String description = types.getString("LOCAL_TYPE_NAME");
231: typeMap.put(type, description);
232: }
233:
234: /*
235: ** Oracle NUMBER columns are type 3, but the Oracle JDBC
236: ** driver doesn't tell me that. Put it in manually...
237: */
238:
239: Integer oracleNumber = new Integer(3);
240:
241: if (!typeMap.containsKey(oracleNumber))
242: typeMap.put(oracleNumber, "NUMBER");
243: }
244:
245: public void finished() {
246: if (!stopped) {
247: columnModel = newColumnModel;
248: fireEvent(SchemaColumnModel.this , "columns", "updated");
249: }
250:
251: columnLoader = null;
252: }
253: }
254: }
|