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.sql.Statement;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.List;
14 import com.quantum.adapters.AdapterFactory;
15 import com.quantum.adapters.DatabaseAdapter;
16 import com.quantum.sql.MultiSQLServer;
17 import com.quantum.sql.SQLMetaDataResults;
18 import com.quantum.util.sql.SQLStates;
21 * This class models a table or view.
25 abstract class EntityImpl implements Entity {
27 // The JDBC-ODBC Driver is more happy if you look up metadata values
28 // using the column number than if you use the column name
30 private static final int INDEX_METADATA_INDEX_NAME = 6;
31 private static final int INDEX_METADATA_COLUMN_NAME = 9;
32 private static final int INDEX_METADATA_ASC_OR_DESC = 10;
34 private static final int PRIMARY_KEYS_METADATA_COLUMN_NAME = 4;
35 private static final int PRIMARY_KEYS_METADATA_KEY_SEQ = 5;
37 private static final int COLUMN_METADATA_COLUMN_NAME = 4;
38 private static final int COLUMN_METATDATA_DATA_TYPE = 5;
39 private static final int COLUMN_METATDATA_TYPE_NAME = 6;
40 private static final int COLUMN_METADATA_COLUMN_SIZE = 7;
41 private static final int COLUMN_METADATA_DECIMAL_DIGITS = 9;
42 private static final int COLUMN_METADATA_REMARKS = 12;
43 private static final int COLUMN_METADATA_ORDINAL_POSITION = 17;
44 private static final int COLUMN_METADATA_IS_NULLABLE = 18;
46 private String schema;
49 private Bookmark bookmark;
50 private Boolean exists = Boolean.TRUE;
51 private boolean isSynonym = false; // Tells if its a synonym or not
52 // Columns will be cached in this array, as sometimes asking for them to the JDBC driver is very costy
53 // (for example in Oracle when synonyms and remarks are asked for )
54 private Column[] columns = null;
56 public EntityImpl(Bookmark bookmark, String schema, String name, String type, boolean isSynonym) {
60 this.bookmark = bookmark;
61 this.isSynonym = isSynonym;
63 public Bookmark getBookmark() {
66 public String getName() {
69 public String getSchema() {
72 public String getType() {
75 public String getQualifiedName() {
76 return (this.schema == null || this.schema.length() == 0) ?
77 this.name : this.schema + "." + this.name;
79 public Column getColumn(String columnName) throws NotConnectedException, SQLException {
81 if (this.columns == null) this.columns = getColumns();
82 for (int i = 0, length = (this.columns == null) ? 0 : this.columns.length;
83 column == null && i < length;
85 if (columnName != null && columnName.equals(this.columns[i].getName())) {
86 column = this.columns[i];
91 public Column[] getColumns() throws NotConnectedException, SQLException {
92 if (this.columns != null) return this.columns;
93 Connection connection = this.bookmark.getConnection();
95 this.columns = getColumnsFromMetaData(connection);
97 } catch (SQLException e) {
98 if (SQLStates.ODBC_DRIVER_NOT_CAPABLE.equals(e.getSQLState())
99 && AdapterFactory.JDBC_ODBC_BRIDGE.equals(
100 getBookmark().getJDBCDriver().getType())) {
101 this.columns = getColumnsFromQuery(connection);
113 * @throws SQLException
115 private Column[] getColumnsFromMetaData(Connection connection) throws SQLException {
116 Map temp = new HashMap();
117 DatabaseMetaData metaData = connection.getMetaData();
118 ResultSet resultSet = metaData.getColumns(null, getSchema(), getName(), null);
120 while (resultSet.next()) {
121 ColumnImpl column = new ColumnImpl(
123 resultSet.getString(COLUMN_METADATA_COLUMN_NAME),
124 resultSet.getString(COLUMN_METATDATA_TYPE_NAME),
125 resultSet.getInt(COLUMN_METATDATA_DATA_TYPE),
126 resultSet.getInt(COLUMN_METADATA_COLUMN_SIZE),
127 resultSet.getInt(COLUMN_METADATA_DECIMAL_DIGITS),
128 "YES".equalsIgnoreCase(resultSet.getString(COLUMN_METADATA_IS_NULLABLE)),
129 resultSet.getInt(COLUMN_METADATA_ORDINAL_POSITION),
130 resultSet.getString(COLUMN_METADATA_REMARKS)
132 temp.put(column.getName(), column);
138 resultSet = metaData.getPrimaryKeys(null, getSchema(), getName());
140 while (resultSet.next()) {
141 String name = resultSet.getString(PRIMARY_KEYS_METADATA_COLUMN_NAME);
142 short keySequence = resultSet.getShort(PRIMARY_KEYS_METADATA_KEY_SEQ);
143 ColumnImpl column = (ColumnImpl) temp.get(name);
144 if (column != null) {
145 column.setPrimaryKeyOrder(keySequence);
150 List columnList = Collections.synchronizedList(
151 new ArrayList(temp.values()));
152 Collections.sort(columnList);
153 return (Column[]) columnList.toArray(new Column[columnList.size()]);
161 * Some databases, (in particular, MS Access under ODBC) aren't terribly friendly
162 * about supporting metadata. This method scrapes out the data the old-fashioned way.
166 * @throws SQLException
168 private Column[] getColumnsFromQuery(Connection connection) throws SQLException {
169 List temp = new ArrayList();
170 SQLMetaDataResults results =
171 (SQLMetaDataResults) MultiSQLServer.getInstance().getMetaData(
173 SQLMetaDataResults.Row[] rows = results.getRows();
174 for (int i = 0, length = results.getRowCount(); i < length; i++) {
175 ColumnImpl column = new ColumnImpl(
177 (String) rows[i].get(1),
178 (String) rows[i].get(2),
179 ((Integer) rows[i].get(7)).intValue(),
180 ((Long) rows[i].get(3)).longValue(),
181 ((Integer) rows[i].get(4)).intValue(),
182 "Nullable".equalsIgnoreCase((String) rows[i].get(5)),
186 return (Column[]) temp.toArray(new Column[temp.size()]);
189 * Some JDBC drivers (Oracle for example) won't return the comments
190 * We recheck with a custom query, if it's defined
191 * @param iniComment The already got comment
192 * @param tableName The fully qualified table name
193 * @param columnName The column name
195 * NO LONGER USED, there is a parameter (remarksReporting) in the JDBC connection that makes ORACLE return the
196 * remarks for tables and columns. Is slower, so an option will be used.
198 * The function is kept in case other JDBC drivers have the same problem
200 private String getComments( String iniComment, String tableName, String columnName) {
201 if (iniComment != null && iniComment.length() > 0)
205 Connection con = this.bookmark.getConnection();
206 DatabaseAdapter adapter = this.bookmark.getAdapter();
207 Statement stmt = con.createStatement();
209 if (adapter != null && stmt != null
210 && adapter.getCommentsQuery(tableName, columnName) != null) {
212 stmt.execute(adapter.getCommentsQuery(tableName, columnName));
213 ResultSet set = stmt.getResultSet();
216 comment = set.getString(1);
225 } catch (NotConnectedException e) {
226 } catch (SQLException e) {
232 public Index[] getIndexes() {
234 List indexList = new ArrayList();
235 Map temp = new HashMap();
237 Connection connection = this.bookmark.getConnection();
238 DatabaseMetaData metaData = connection.getMetaData();
239 ResultSet resultSet = metaData.getIndexInfo(null, getSchema(), getName(), false, false);
241 while (resultSet.next()) {
242 String indexName = resultSet.getString(INDEX_METADATA_INDEX_NAME);
243 IndexImpl index = (IndexImpl) temp.get(indexName);
245 index = new IndexImpl(this, indexName);
246 temp.put(indexName, index);
248 String columnName = resultSet.getString(INDEX_METADATA_COLUMN_NAME);
249 String ascending = resultSet.getString(INDEX_METADATA_ASC_OR_DESC);
250 index.addColumn(columnName, ascending == null
251 ? null : (ascending.toUpperCase().startsWith("A")
252 ? Boolean.TRUE : Boolean.FALSE));
255 indexList.addAll(temp.values());
257 } catch (NotConnectedException e) {
258 } catch (SQLException e) {
260 return (Index[]) indexList.toArray(new Index[indexList.size()]);
263 public Boolean exists() {
269 * @see com.quantum.model.Entity#getQuotedTableName()
271 public String getQuotedTableName() {
272 return getBookmark().getAdapter().filterTableName(getQualifiedName());
275 public ForeignKey[] getExportedKeys() throws SQLException, NotConnectedException {
276 return this.bookmark.getDatabase().getExportedKeys(getSchema(), getName());
279 public ForeignKey[] getImportedKeys() throws SQLException, NotConnectedException {
280 return this.bookmark.getDatabase().getImportedKeys(getSchema(), getName());
282 public ForeignKey[] getReferences() throws SQLException, NotConnectedException {
283 ForeignKey[] importedKeys = getImportedKeys();
284 ForeignKey[] exportedKeys = getExportedKeys();
286 List list = new ArrayList(); // if we could guarantee JDK 1.4, we'd use LinkedHashSet
287 for (int i = 0, length = importedKeys == null ? 0 : importedKeys.length; i < length; i++) {
288 list.add(importedKeys[i]);
290 for (int i = 0, length = exportedKeys == null ? 0 : exportedKeys.length; i < length; i++) {
291 if (!list.contains(exportedKeys[i])) {
292 list.add(exportedKeys[i]);
295 return (ForeignKey[]) list.toArray(new ForeignKey[list.size()]);
298 public int compareTo(Object object) {
299 Entity that = (Entity) object;
300 if (that.getQualifiedName() == null && this.getQualifiedName() != null) {
302 } else if (this.getQualifiedName() == null && that.getQualifiedName() != null) {
304 } else if (this.getQualifiedName() == null && that.getQualifiedName() == null) {
307 return this.getQualifiedName().compareTo(that.getQualifiedName());
312 * @return Returns the isSynonym.
314 public boolean isSynonym() {