Quantum version 2.4.1
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.quantum.sql / src / com / quantum / model / Database.java
1 package com.quantum.model;
2
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;
11 import java.util.Set;
12
13 import com.quantum.adapters.DatabaseAdapter;
14 import com.quantum.sql.MultiSQLServer;
15 import com.quantum.sql.SQLResultSetResults;
16
17 /**
18  * @author BC
19  */
20 public class Database {
21     
22         private static final int TABLE_METADATA_TABLE_SCHEM = 2;
23         private static final int TABLE_METADATA_TABLE_NAME = 3;
24         
25         private static final int TABLE_TYPE_METADATA_TABLE_TYPE = 1;
26
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;
36         
37         private static final int TYPE_INFO_METADATA_TYPE_NAME = 1;
38         private static final int TYPE_INFO_METADATA_DATA_TYPE = 2;
39         
40         private DatabaseAdapter databaseAdapter;
41     private Bookmark bookmark;
42     
43     public Database(Bookmark bookmark) {
44         this.bookmark = bookmark;
45         this.databaseAdapter = bookmark.getAdapter();
46     }
47
48     private static final String[] ALL_TABLE_TYPES = { 
49         Entity.TABLE_TYPE, 
50         Entity.VIEW_TYPE, 
51         Entity.SEQUENCE_TYPE };
52         
53     private static final List STANDARD_TABLE_TYPES = 
54         Collections.synchronizedList(new ArrayList());
55         
56     static {
57         for (int i = 0, length = (ALL_TABLE_TYPES == null) ? 0 : ALL_TABLE_TYPES.length;
58             i < length;
59             i++) {
60             STANDARD_TABLE_TYPES.add(ALL_TABLE_TYPES[i]);
61         }
62     }
63     
64     public String[] getEntityTypes() 
65         throws NotConnectedException, SQLException {
66         return getEntityTypes(this.bookmark.getConnection());
67     }
68     
69     public String getUsername() throws NotConnectedException, SQLException {
70         return getMetaData().getUserName();
71     }
72
73
74     /**
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 
77      * Sequences.</p>
78      * 
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>
82      * 
83      * @param connection
84      * @return
85      * @throws SQLException
86      */
87     public String[] getEntityTypes(Connection connection) throws SQLException {
88         
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);
96         }
97         
98         DatabaseMetaData metaData = connection.getMetaData();
99         ResultSet resultSet = metaData.getTableTypes();
100         while (resultSet.next()) {
101             String type = resultSet.getString(TABLE_TYPE_METADATA_TABLE_TYPE);
102             if (type != null) {
103                 // Informix, in particular, pads this with extra spaces
104                 type = type.trim();
105             }
106             if (STANDARD_TABLE_TYPES.contains(type)) {
107                 set.add(type);
108             }
109         }
110         
111         return (String[]) set.toArray(new String[set.size()]);
112     }
113
114     public String getInformation() throws SQLException {
115         try {
116             DatabaseMetaData metaData = getMetaData();
117         
118             return metaData == null ? null : metaData.getDatabaseProductName() + " " 
119                     + metaData.getDatabaseProductVersion();
120         } catch (NotConnectedException e) {
121             // TODO: think about this...
122             return "";
123         }
124     }
125     
126     /**
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.
131      * 
132      * @param bookmark -
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
136      * @param schema -
137      *     the schema from which to extract
138      * @param type -
139      *     the type ("VIEW", "TABLE", etc.) of entities to extract or null
140      *     if all entity types should be extracted
141      * @return 
142      *     an array of entity objects representing the tables, views and sequences.
143      * @throws SQLException
144      */
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;
150     }
151     
152     protected Entity[] getEntities(Bookmark bookmark, Connection connection, Schema schema, String type) 
153         throws SQLException {
154         
155         List list = new ArrayList();
156         String[] types = (type == null) ? ALL_TABLE_TYPES : new String[] { type };
157             
158         for (int i = 0; i < types.length; i++) {
159             list.addAll(getEntitiesList(bookmark, connection, types[i], schema));
160         }
161
162         return (Entity[]) list.toArray(new Entity[list.size()]);
163     }
164
165     protected List getEntitiesList(Bookmark bookmark, Connection connection, String type, Schema schema)
166         throws SQLException {
167
168         String sql = getSQL(bookmark, type, schema);
169         List list = new ArrayList();
170         SQLResultSetResults results = null;
171         if (sql != 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) {
184                         list.add(entity);
185                     }
186                 }
187             }
188         }
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 });
197                 } else {
198                         set = metaData.getTables(null, null, "%", new String[] { type });
199                 }
200             
201         while (set.next()) {
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();
206
207             if (tableName != null && tableName.length() > 0) {
208                 Entity entity = EntityFactory.getInstance().create(bookmark, tempSchema, tableName, type);
209                 if (entity != null) {
210                     list.add(entity);
211                 }
212             }
213         }
214         set.close();
215         return list;
216     }
217     
218     public DataType[] getTypes() throws NotConnectedException, SQLException {
219         DatabaseMetaData metaData = getMetaData();
220         List list = new ArrayList();
221         ResultSet results = metaData.getTypeInfo();
222         try {
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));
227                 }
228         } finally {
229                 results.close();
230         }
231         return (DataType[]) list.toArray(new DataType[list.size()]);
232     }
233
234
235     /**
236          * @return
237          * @throws NotConnectedException
238          * @throws SQLException
239          */
240         private DatabaseMetaData getMetaData() throws NotConnectedException, SQLException {
241                 Connection connection = this.bookmark.getConnection();
242         DatabaseMetaData metaData = connection.getMetaData();
243                 return metaData;
244         }
245
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());
253         } else {
254             return null;
255         }
256     }
257         
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));
263         }
264
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));
270         }
271
272         /**
273          * @param list
274          * @param resultSet
275          * @return
276          * @throws SQLException
277          */
278         private ForeignKey[] getForeignKeys(List list, ResultSet resultSet) throws SQLException {
279                 ForeignKeyImpl foreignKey = null;
280                 
281                 int lowestKeySequence = Integer.MAX_VALUE;
282                 try {
283                         while (resultSet.next()) {
284                                 int keySequence = resultSet.getInt(FOREIGN_KEY_METADATA_KEY_SEQ);
285                                 lowestKeySequence = Math.min(lowestKeySequence, keySequence);
286                                 
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));
296                                 }
297                                 
298                                 foreignKey.addColumns(
299                                                 resultSet.getString(FOREIGN_KEY_METADATA_PKCOLUMN_NAME), 
300                                                 resultSet.getString(FOREIGN_KEY_METADATA_FKCOLUMN_NAME));
301                         }
302                         return (ForeignKey[]) list.toArray(new ForeignKey[list.size()]);
303                 } finally {
304                         resultSet.close();
305                 }
306         }
307
308         /**
309          * @return
310          * @throws SQLException
311          * @throws NotConnectedException
312          */
313         public Schema[] getSchemas() throws NotConnectedException, SQLException {
314                 DatabaseMetaData metaData = getMetaData();
315                 List list = new ArrayList();
316                 ResultSet resultSet = metaData.getSchemas();
317                 try {
318                         while (resultSet.next()) {
319                                 String schemaName = resultSet.getString("TABLE_SCHEM");
320                                 list.add(new Schema(schemaName));
321                         }
322                         return (Schema[]) list.toArray(new Schema[list.size()]);
323                 } finally {
324                         resultSet.close();
325                 }
326         }
327 }