1 package com.quantum.model;
3 import java.sql.Connection;
4 import java.sql.DatabaseMetaData;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.HashSet;
10 import java.util.List;
13 import com.quantum.adapters.DatabaseAdapter;
14 import com.quantum.sql.MultiSQLServer;
15 import com.quantum.sql.SQLResultSetResults;
20 public class Database {
22 private static final int TABLE_METADATA_TABLE_SCHEM = 2;
23 private static final int TABLE_METADATA_TABLE_NAME = 3;
25 private static final int TABLE_TYPE_METADATA_TABLE_TYPE = 1;
27 private static final int FOREIGN_KEY_METADATA_PKTABLE_SCHEM = 2;
28 private static final int FOREIGN_KEY_METADATA_PKTABLE_NAME = 3;
29 private static final int FOREIGN_KEY_METADATA_PKCOLUMN_NAME = 4;
30 private static final int FOREIGN_KEY_METADATA_FKTABLE_SCHEM = 6;
31 private static final int FOREIGN_KEY_METADATA_FKTABLE_NAME = 7;
32 private static final int FOREIGN_KEY_METADATA_FKCOLUMN_NAME = 8;
33 private static final int FOREIGN_KEY_METADATA_KEY_SEQ = 9;
34 private static final int FOREIGN_KEY_METADATA_DELETE_RULE = 11;
35 private static final int FOREIGN_KEY_METADATA_FK_NAME = 12;
37 private static final int TYPE_INFO_METADATA_TYPE_NAME = 1;
38 private static final int TYPE_INFO_METADATA_DATA_TYPE = 2;
40 private DatabaseAdapter databaseAdapter;
41 private Bookmark bookmark;
43 public Database(Bookmark bookmark) {
44 this.bookmark = bookmark;
45 this.databaseAdapter = bookmark.getAdapter();
48 private static final String[] ALL_TABLE_TYPES = {
51 Entity.SEQUENCE_TYPE };
53 private static final List STANDARD_TABLE_TYPES =
54 Collections.synchronizedList(new ArrayList());
57 for (int i = 0, length = (ALL_TABLE_TYPES == null) ? 0 : ALL_TABLE_TYPES.length;
60 STANDARD_TABLE_TYPES.add(ALL_TABLE_TYPES[i]);
64 public String[] getEntityTypes()
65 throws NotConnectedException, SQLException {
66 return getEntityTypes(this.bookmark.getConnection());
69 public String getUsername() throws NotConnectedException, SQLException {
70 return getMetaData().getUserName();
75 * <p>This method returns a list of entity types supported by the database
76 * adapter. This list will always be limited to Tables, Views and
79 * <p>Not all databases support all types. MySQL only supports
80 * Tables. Informix supports Tables and Views. Oracle and DB2 support
81 * Tables, Views and Sequences.</p>
85 * @throws SQLException
87 public String[] getEntityTypes(Connection connection) throws SQLException {
89 Set set = new HashSet();
90 if (this.databaseAdapter.getShowTableQuery(this.bookmark.getUsername()) != null) {
91 set.add(Entity.TABLE_TYPE);
92 } else if (this.databaseAdapter.getShowViewQuery(this.bookmark.getUsername()) != null) {
93 set.add(Entity.VIEW_TYPE);
94 } else if (this.databaseAdapter.getShowSequenceQuery(this.bookmark.getUsername()) != null) {
95 set.add(Entity.SEQUENCE_TYPE);
98 DatabaseMetaData metaData = connection.getMetaData();
99 ResultSet resultSet = metaData.getTableTypes();
100 while (resultSet.next()) {
101 String type = resultSet.getString(TABLE_TYPE_METADATA_TABLE_TYPE);
103 // Informix, in particular, pads this with extra spaces
106 if (STANDARD_TABLE_TYPES.contains(type)) {
111 return (String[]) set.toArray(new String[set.size()]);
114 public String getInformation() throws SQLException {
116 DatabaseMetaData metaData = getMetaData();
118 return metaData == null ? null : metaData.getDatabaseProductName() + " "
119 + metaData.getDatabaseProductVersion();
120 } catch (NotConnectedException e) {
121 // TODO: think about this...
127 * Get a list of entities (tables, views, sequences) for a particular
128 * bookmark. This function is usually not redefined because it gives
129 * an external interface. You will usually redefine the getShowTableQuery(),
130 * getShowViewQuery(), etc.
133 * the bookmark that describes the database that is being accessed.
134 * @param passwordFinder -
135 * a utility class that knows how to obtain a password, if required
137 * the schema from which to extract
139 * the type ("VIEW", "TABLE", etc.) of entities to extract or null
140 * if all entity types should be extracted
142 * an array of entity objects representing the tables, views and sequences.
143 * @throws SQLException
145 public Entity[] getEntities(Bookmark bookmark, Schema schema, String type)
146 throws SQLException, NotConnectedException {
147 Connection connection = bookmark.getConnection();
148 Entity[] result = getEntities(bookmark, connection, schema, type);
149 return (result == null) ? new Entity[0] : result;
152 protected Entity[] getEntities(Bookmark bookmark, Connection connection, Schema schema, String type)
153 throws SQLException {
155 List list = new ArrayList();
156 String[] types = (type == null) ? ALL_TABLE_TYPES : new String[] { type };
158 for (int i = 0; i < types.length; i++) {
159 list.addAll(getEntitiesList(bookmark, connection, types[i], schema));
162 return (Entity[]) list.toArray(new Entity[list.size()]);
165 protected List getEntitiesList(Bookmark bookmark, Connection connection, String type, Schema schema)
166 throws SQLException {
168 String sql = getSQL(bookmark, type, schema);
169 List list = new ArrayList();
170 SQLResultSetResults results = null;
172 results = (SQLResultSetResults) MultiSQLServer.getInstance().execute(
173 bookmark, connection, sql, Integer.MAX_VALUE);
174 for (int i = 1, size = (results == null) ? 0 : results.getRowCount(); i <= size; i++) {
175 String schemaName = results.getColumnCount() == 1
176 ? schema.getName() : results.getElement(1, i).toString();
177 String tableName = results.getColumnCount() == 1
178 ? results.getElement(1, i).toString()
179 : results.getElement(2, i).toString();
180 if (tableName != null && tableName.length() > 0) {
181 Entity entity = EntityFactory.getInstance().create(
182 bookmark, schemaName, tableName, type);
183 if (entity != null) {
189 // If we have some results, we go back
190 if (results != null) return list;
191 // Else, we try the JDBC driver
192 DatabaseMetaData metaData = connection.getMetaData();
193 // getTables needs a null schema to get all the schemas. So we don't pass a "" schema, but a null one
194 ResultSet set = null;
195 if (metaData.supportsSchemasInTableDefinitions()) {
196 set = metaData.getTables(null, (schema != null) ? schema.getName() : null, "%", new String[] { type });
198 set = metaData.getTables(null, null, "%", new String[] { type });
202 String tempSchema = set.getString(TABLE_METADATA_TABLE_SCHEM);
203 tempSchema = (tempSchema == null) ? "" : tempSchema.trim();
204 String tableName = set.getString(TABLE_METADATA_TABLE_NAME);
205 tableName = (tableName == null) ? "" : tableName.trim();
207 if (tableName != null && tableName.length() > 0) {
208 Entity entity = EntityFactory.getInstance().create(bookmark, tempSchema, tableName, type);
209 if (entity != null) {
218 public DataType[] getTypes() throws NotConnectedException, SQLException {
219 DatabaseMetaData metaData = getMetaData();
220 List list = new ArrayList();
221 ResultSet results = metaData.getTypeInfo();
223 while (results.next()) {
224 String name = results.getString(TYPE_INFO_METADATA_TYPE_NAME);
225 int type = results.getInt(TYPE_INFO_METADATA_DATA_TYPE);
226 list.add(new DataType(type, name));
231 return (DataType[]) list.toArray(new DataType[list.size()]);
237 * @throws NotConnectedException
238 * @throws SQLException
240 private DatabaseMetaData getMetaData() throws NotConnectedException, SQLException {
241 Connection connection = this.bookmark.getConnection();
242 DatabaseMetaData metaData = connection.getMetaData();
246 private String getSQL(Bookmark bookmark, String type, Schema schema) {
247 if (Entity.TABLE_TYPE.equals(type)) {
248 return this.databaseAdapter.getShowTableQuery(schema.getName());
249 } else if (Entity.VIEW_TYPE.equals(type)) {
250 return this.databaseAdapter.getShowViewQuery(schema.getName());
251 } else if (Entity.SEQUENCE_TYPE.equals(type)) {
252 return this.databaseAdapter.getShowSequenceQuery(schema.getName());
258 public ForeignKey[] getExportedKeys(String schema, String entityName)
259 throws NotConnectedException, SQLException {
260 DatabaseMetaData metaData = getMetaData();
261 List list = new ArrayList();
262 return getForeignKeys(list, metaData.getExportedKeys(null, schema, entityName));
265 public ForeignKey[] getImportedKeys(String schema, String entityName)
266 throws NotConnectedException, SQLException {
267 DatabaseMetaData metaData = getMetaData();
268 List list = new ArrayList();
269 return getForeignKeys(list, metaData.getImportedKeys(null, schema, entityName));
276 * @throws SQLException
278 private ForeignKey[] getForeignKeys(List list, ResultSet resultSet) throws SQLException {
279 ForeignKeyImpl foreignKey = null;
281 int lowestKeySequence = Integer.MAX_VALUE;
283 while (resultSet.next()) {
284 int keySequence = resultSet.getInt(FOREIGN_KEY_METADATA_KEY_SEQ);
285 lowestKeySequence = Math.min(lowestKeySequence, keySequence);
287 if (keySequence == lowestKeySequence || foreignKey == null) {
288 foreignKey = new ForeignKeyImpl();
289 list.add(foreignKey);
290 foreignKey.setName(resultSet.getString(FOREIGN_KEY_METADATA_FK_NAME));
291 foreignKey.setDeleteRule(resultSet.getShort(FOREIGN_KEY_METADATA_DELETE_RULE));
292 foreignKey.setForeignEntitySchema(resultSet.getString(FOREIGN_KEY_METADATA_FKTABLE_SCHEM));
293 foreignKey.setForeignEntityName(resultSet.getString(FOREIGN_KEY_METADATA_FKTABLE_NAME));
294 foreignKey.setLocalEntitySchema(resultSet.getString(FOREIGN_KEY_METADATA_PKTABLE_SCHEM));
295 foreignKey.setLocalEntityName(resultSet.getString(FOREIGN_KEY_METADATA_PKTABLE_NAME));
298 foreignKey.addColumns(
299 resultSet.getString(FOREIGN_KEY_METADATA_PKCOLUMN_NAME),
300 resultSet.getString(FOREIGN_KEY_METADATA_FKCOLUMN_NAME));
302 return (ForeignKey[]) list.toArray(new ForeignKey[list.size()]);
310 * @throws SQLException
311 * @throws NotConnectedException
313 public Schema[] getSchemas() throws NotConnectedException, SQLException {
314 DatabaseMetaData metaData = getMetaData();
315 List list = new ArrayList();
316 ResultSet resultSet = metaData.getSchemas();
318 while (resultSet.next()) {
319 String schemaName = resultSet.getString("TABLE_SCHEM");
320 list.add(new Schema(schemaName));
322 return (Schema[]) list.toArray(new Schema[list.size()]);