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.Collection;
9 import java.util.Collections;
10 import java.util.HashSet;
11 import java.util.List;
14 import com.quantum.adapters.DatabaseAdapter;
15 import com.quantum.sql.MultiSQLServer;
16 import com.quantum.sql.SQLResultSetResults;
21 public class Database {
23 private static final int TABLE_METADATA_TABLE_SCHEM = 2;
24 private static final int TABLE_METADATA_TABLE_NAME = 3;
26 private static final int TABLE_TYPE_METADATA_TABLE_TYPE = 1;
28 private static final int FOREIGN_KEY_METADATA_PKTABLE_SCHEM = 2;
29 private static final int FOREIGN_KEY_METADATA_PKTABLE_NAME = 3;
30 private static final int FOREIGN_KEY_METADATA_PKCOLUMN_NAME = 4;
31 private static final int FOREIGN_KEY_METADATA_FKTABLE_SCHEM = 6;
32 private static final int FOREIGN_KEY_METADATA_FKTABLE_NAME = 7;
33 private static final int FOREIGN_KEY_METADATA_FKCOLUMN_NAME = 8;
34 private static final int FOREIGN_KEY_METADATA_KEY_SEQ = 9;
35 private static final int FOREIGN_KEY_METADATA_DELETE_RULE = 11;
36 private static final int FOREIGN_KEY_METADATA_FK_NAME = 12;
38 private static final int TYPE_INFO_METADATA_TYPE_NAME = 1;
39 private static final int TYPE_INFO_METADATA_DATA_TYPE = 2;
40 private static final int TYPE_INFO_METADATA_PRECISION = 3;
41 private static final int TYPE_INFO_METADATA_LITERAL_PREFIX = 4;
42 private static final int TYPE_INFO_METADATA_LITERAL_SUFFIX = 5;
43 private static final int TYPE_INFO_METADATA_CREATE_PARMS = 6;
45 private DatabaseAdapter databaseAdapter;
46 private Bookmark bookmark;
48 private List entityTypes;
50 public Database(Bookmark bookmark) {
51 this.bookmark = bookmark;
52 this.databaseAdapter = bookmark.getAdapter();
55 private static final String[] ALL_TABLE_TYPES = {
58 Entity.SEQUENCE_TYPE };
60 private static final List STANDARD_TABLE_TYPES =
61 Collections.synchronizedList(new ArrayList());
64 for (int i = 0, length = (ALL_TABLE_TYPES == null) ? 0 : ALL_TABLE_TYPES.length;
67 STANDARD_TABLE_TYPES.add(ALL_TABLE_TYPES[i]);
71 public synchronized String[] getEntityTypes()
72 throws NotConnectedException, SQLException {
73 if (this.entityTypes == null) {
74 Collection collection = initializeEntityTypes(this.bookmark.getConnection());
75 this.entityTypes = Collections.synchronizedList(new ArrayList(collection));
77 return (String[]) this.entityTypes.toArray(new String[this.entityTypes.size()]);
80 public String getUsername() throws NotConnectedException, SQLException {
81 return getMetaData().getUserName();
86 * <p>This method returns a set of entity types supported by the database
87 * adapter. This list will always be limited to Tables, Views and
90 * <p>Not all databases support all types. MySQL only supports
91 * Tables. Informix supports Tables and Views. Oracle and DB2 support
92 * Tables, Views and Sequences.</p>
95 * @return a set of Strings, typically "TABLE", "VIEW", and "SEQUENCE"
96 * @throws SQLException
98 private Set initializeEntityTypes(Connection connection) throws SQLException {
100 Set set = new HashSet();
101 if (this.databaseAdapter.getShowTableQuery(this.bookmark.getUsername()) != null) {
102 set.add(Entity.TABLE_TYPE);
103 } else if (this.databaseAdapter.getShowViewQuery(this.bookmark.getUsername()) != null) {
104 set.add(Entity.VIEW_TYPE);
105 } else if (this.databaseAdapter.getShowSequenceQuery(this.bookmark.getUsername()) != null) {
106 set.add(Entity.SEQUENCE_TYPE);
109 DatabaseMetaData metaData = connection.getMetaData();
110 ResultSet resultSet = metaData.getTableTypes();
111 while (resultSet.next()) {
112 String type = resultSet.getString(TABLE_TYPE_METADATA_TABLE_TYPE);
114 // Informix, in particular, pads this with extra spaces
117 if (STANDARD_TABLE_TYPES.contains(type)) {
124 public String getInformation() throws SQLException {
126 DatabaseMetaData metaData = getMetaData();
128 return metaData == null ? null : metaData.getDatabaseProductName() + " "
129 + metaData.getDatabaseProductVersion();
130 } catch (NotConnectedException e) {
131 // TODO: think about this...
137 * Get a list of entities (tables, views, sequences) for a particular
138 * bookmark. This function is usually not redefined because it gives
139 * an external interface. You will usually redefine the getShowTableQuery(),
140 * getShowViewQuery(), etc.
143 * the bookmark that describes the database that is being accessed.
144 * @param passwordFinder -
145 * a utility class that knows how to obtain a password, if required
147 * the schema from which to extract
149 * the type ("VIEW", "TABLE", etc.) of entities to extract or null
150 * if all entity types should be extracted
152 * an array of entity objects representing the tables, views and sequences.
153 * @throws SQLException
155 public Entity[] getEntities(Bookmark bookmark, Schema schema, String type)
156 throws SQLException, NotConnectedException {
157 Connection connection = bookmark.getConnection();
158 Entity[] result = getEntities(bookmark, connection, schema, type);
159 return (result == null) ? new Entity[0] : result;
162 protected Entity[] getEntities(Bookmark bookmark, Connection connection, Schema schema, String type)
163 throws SQLException {
165 List list = new ArrayList();
166 String[] types = (type == null) ? ALL_TABLE_TYPES : new String[] { type };
168 for (int i = 0; i < types.length; i++) {
169 list.addAll(getEntitiesList(bookmark, connection, types[i], schema));
170 // TODO: This should be polished so that synonyms can be shown with different icons as regular Entities
171 list.addAll(getSynonymsList(bookmark, connection, types[i], schema));
174 return (Entity[]) list.toArray(new Entity[list.size()]);
177 protected List getEntitiesList(Bookmark bookmark, Connection connection, String type, Schema schema)
178 throws SQLException {
180 List list = new ArrayList();
181 // We try first the JDBC driver
182 DatabaseMetaData metaData = connection.getMetaData();
183 // getTables needs a null schema to get all the schemas. So we don't pass a "" schema, but a null one
184 ResultSet set = null;
185 if (metaData.supportsSchemasInTableDefinitions()) {
186 set = metaData.getTables(null, (schema != null) ? schema.getName() : null, "%", new String[] { type });
188 set = metaData.getTables(null, null, "%", new String[] { type });
192 String tempSchema = set.getString(TABLE_METADATA_TABLE_SCHEM);
193 tempSchema = (tempSchema == null) ? "" : tempSchema.trim();
194 String tableName = set.getString(TABLE_METADATA_TABLE_NAME);
195 tableName = (tableName == null) ? "" : tableName.trim();
197 if (tableName != null && tableName.length() > 0) {
198 Entity entity = EntityFactory.getInstance().create(bookmark, tempSchema, tableName, type, false);
199 if (entity != null) {
205 // If we have some results, then the JDBC driver is working,
206 // so we return the results and quit
211 // If no results, we check also the sql query to get the list of entities
212 SQLResultSetResults results = null;
213 // Get the proper sql query to the appropiate type of entity
214 String sql = getSQL(bookmark, type, schema);
215 // If nothing returned, too bad, it seems there is no sql query for that database and entity type
217 results = (SQLResultSetResults) MultiSQLServer.getInstance().execute(
218 bookmark, connection, sql, Integer.MAX_VALUE);
219 for (int i = 1, size = (results == null) ? 0 : results.getRowCount(); i <= size; i++) {
220 String schemaName = results.getColumnCount() == 1
221 ? schema.getName() : results.getElement(1, i).toString();
222 if (schemaName != null) {
223 schemaName = schemaName.trim();
225 String tableName = results.getColumnCount() == 1
226 ? results.getElement(1, i).toString()
227 : results.getElement(2, i).toString();
228 if (tableName != null && tableName.length() > 0) {
229 Entity entity = EntityFactory.getInstance().create(
230 bookmark, schemaName, tableName, type, false);
231 if (entity != null) {
240 * Returns a list with the synonym objects of the given type, using a query
246 * @throws SQLException
248 protected List getSynonymsList(Bookmark bookmark, Connection connection, String type, Schema schema)
249 throws SQLException {
251 List list = new ArrayList();
252 // We try first the JDBC driver
253 DatabaseMetaData metaData = connection.getMetaData();
254 SQLResultSetResults results = null;
255 // Get the proper sql query to the appropiate type of entity
256 String sql = this.databaseAdapter.getShowSynonymsQuery(schema.getName(), type);
257 // If nothing returned, too bad, it seems there is no sql query for that database and entity type
259 results = (SQLResultSetResults) MultiSQLServer.getInstance().execute(
260 bookmark, connection, sql, Integer.MAX_VALUE);
261 for (int i = 1, size = (results == null) ? 0 : results.getRowCount(); i <= size; i++) {
262 String schemaName = results.getColumnCount() == 1
263 ? schema.getName() : results.getElement(1, i).toString();
264 if (schemaName != null) {
265 schemaName = schemaName.trim();
267 String tableName = results.getColumnCount() == 1
268 ? results.getElement(1, i).toString()
269 : results.getElement(2, i).toString();
270 if (tableName != null && tableName.length() > 0) {
271 Entity entity = EntityFactory.getInstance().create(
272 bookmark, schemaName, tableName, type, true);
273 if (entity != null) {
282 public DataType[] getTypes() throws NotConnectedException, SQLException {
283 DatabaseMetaData metaData = getMetaData();
284 List list = new ArrayList();
285 ResultSet results = metaData.getTypeInfo();
287 while (results.next()) {
288 list.add(new DataType(
289 results.getInt(TYPE_INFO_METADATA_DATA_TYPE),
290 results.getString(TYPE_INFO_METADATA_TYPE_NAME),
291 results.getLong(TYPE_INFO_METADATA_PRECISION),
292 results.getString(TYPE_INFO_METADATA_LITERAL_PREFIX),
293 results.getString(TYPE_INFO_METADATA_LITERAL_SUFFIX),
294 results.getString(TYPE_INFO_METADATA_CREATE_PARMS)
300 return (DataType[]) list.toArray(new DataType[list.size()]);
306 * @throws NotConnectedException
307 * @throws SQLException
309 private DatabaseMetaData getMetaData() throws NotConnectedException, SQLException {
310 Connection connection = this.bookmark.getConnection();
311 DatabaseMetaData metaData = connection.getMetaData();
315 private String getSQL(Bookmark bookmark, String type, Schema schema) {
316 if (Entity.TABLE_TYPE.equals(type)) {
317 return this.databaseAdapter.getShowTableQuery(schema.getName());
318 } else if (Entity.VIEW_TYPE.equals(type)) {
319 return this.databaseAdapter.getShowViewQuery(schema.getName());
320 } else if (Entity.SEQUENCE_TYPE.equals(type)) {
321 return this.databaseAdapter.getShowSequenceQuery(schema.getName());
327 public ForeignKey[] getExportedKeys(String schema, String entityName)
328 throws NotConnectedException, SQLException {
329 DatabaseMetaData metaData = getMetaData();
330 List list = new ArrayList();
331 return getForeignKeys(list, metaData.getExportedKeys(null, schema, entityName));
334 public ForeignKey[] getImportedKeys(String schema, String entityName)
335 throws NotConnectedException, SQLException {
336 DatabaseMetaData metaData = getMetaData();
337 List list = new ArrayList();
338 return getForeignKeys(list, metaData.getImportedKeys(null, schema, entityName));
345 * @throws SQLException
347 private ForeignKey[] getForeignKeys(List list, ResultSet resultSet) throws SQLException {
348 ForeignKeyImpl foreignKey = null;
350 int lowestKeySequence = Integer.MAX_VALUE;
352 while (resultSet.next()) {
353 int keySequence = resultSet.getInt(FOREIGN_KEY_METADATA_KEY_SEQ);
354 lowestKeySequence = Math.min(lowestKeySequence, keySequence);
356 if (keySequence == lowestKeySequence || foreignKey == null) {
357 foreignKey = new ForeignKeyImpl();
358 list.add(foreignKey);
359 foreignKey.setName(resultSet.getString(FOREIGN_KEY_METADATA_FK_NAME));
360 foreignKey.setDeleteRule(resultSet.getShort(FOREIGN_KEY_METADATA_DELETE_RULE));
361 foreignKey.setForeignEntitySchema(resultSet.getString(FOREIGN_KEY_METADATA_FKTABLE_SCHEM));
362 foreignKey.setForeignEntityName(resultSet.getString(FOREIGN_KEY_METADATA_FKTABLE_NAME));
363 foreignKey.setLocalEntitySchema(resultSet.getString(FOREIGN_KEY_METADATA_PKTABLE_SCHEM));
364 foreignKey.setLocalEntityName(resultSet.getString(FOREIGN_KEY_METADATA_PKTABLE_NAME));
367 foreignKey.addColumns(
368 resultSet.getString(FOREIGN_KEY_METADATA_PKCOLUMN_NAME),
369 resultSet.getString(FOREIGN_KEY_METADATA_FKCOLUMN_NAME));
371 return (ForeignKey[]) list.toArray(new ForeignKey[list.size()]);
379 * @throws SQLException
380 * @throws NotConnectedException
382 public Schema[] getSchemas() throws NotConnectedException, SQLException {
383 DatabaseMetaData metaData = getMetaData();
384 List list = new ArrayList();
386 if (metaData.supportsSchemasInTableDefinitions()) {
387 ResultSet resultSet = metaData.getSchemas();
389 while (resultSet.next()) {
390 String schemaName = resultSet.getString("TABLE_SCHEM");
391 list.add(new Schema(schemaName));
397 return (Schema[]) list.toArray(new Schema[list.size()]);