package org.insightech.er.editor.model.dbimport; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.operation.IRunnableWithProgress; import org.insightech.er.Activator; import org.insightech.er.ResourceString; import org.insightech.er.common.exception.InputException; import org.insightech.er.db.sqltype.SqlType; import org.insightech.er.editor.TranslationResources; import org.insightech.er.editor.model.ERDiagram; import org.insightech.er.editor.model.diagram_contents.element.connection.Relation; import org.insightech.er.editor.model.diagram_contents.element.node.table.ERTable; import org.insightech.er.editor.model.diagram_contents.element.node.table.column.Column; import org.insightech.er.editor.model.diagram_contents.element.node.table.column.NormalColumn; import org.insightech.er.editor.model.diagram_contents.element.node.table.index.Index; import org.insightech.er.editor.model.diagram_contents.element.node.table.properties.TableViewProperties; import org.insightech.er.editor.model.diagram_contents.element.node.table.unique_key.ComplexUniqueKey; import org.insightech.er.editor.model.diagram_contents.element.node.view.View; import org.insightech.er.editor.model.diagram_contents.not_element.dictionary.TypeData; import org.insightech.er.editor.model.diagram_contents.not_element.dictionary.UniqueWord; import org.insightech.er.editor.model.diagram_contents.not_element.dictionary.Word; import org.insightech.er.editor.model.diagram_contents.not_element.sequence.Sequence; import org.insightech.er.editor.model.diagram_contents.not_element.tablespace.Tablespace; import org.insightech.er.editor.model.diagram_contents.not_element.trigger.Trigger; import org.insightech.er.editor.model.settings.DBSetting; import org.insightech.er.util.Check; import org.insightech.er.util.Format; public abstract class ImportFromDBManagerBase implements ImportFromDBManager, IRunnableWithProgress { private static Logger logger = Logger .getLogger(ImportFromDBManagerBase.class.getName()); private static final boolean LOG_SQL_TYPE = false; private static final Pattern AS_PATTERN = Pattern .compile("(.+) [aA][sS] (.+)"); protected Connection con; private DatabaseMetaData metaData; protected DBSetting dbSetting; private ERDiagram diagram; private List<DBObject> dbObjectList; private Map<String, ERTable> tableMap; protected Map<String, String> tableCommentMap; protected Map<String, Map<String, ColumnData>> columnDataCash; private Map<String, List<ForeignKeyData>> tableForeignKeyDataMap; private Map<UniqueWord, Word> dictionary; private List<ERTable> importedTables; private List<Sequence> importedSequences; private List<Trigger> importedTriggers; private List<Tablespace> importedTablespaces; private List<View> importedViews; private Exception exception; protected TranslationResources translationResources; private boolean useCommentAsLogicalName; private boolean mergeWord; protected static class ColumnData { public String columnName; public String type; public int size; public int decimalDegits; public int nullable; public String defaultValue; public String description; public String constraint; public String enumData; @Override public String toString() { return "ColumnData [columnName=" + columnName + ", type=" + type + ", size=" + size + ", decimalDegits=" + decimalDegits + "]"; } } private static class ForeignKeyData { private String name; private String sourceTableName; private String sourceSchemaName; private String sourceColumnName; private String targetTableName; private String targetSchemaName; private String targetColumnName; private short updateRule; private short deleteRule; } protected static class PrimaryKeyData { private String columnName; private String constraintName; } public ImportFromDBManagerBase() { this.tableMap = new HashMap<String, ERTable>(); this.tableCommentMap = new HashMap<String, String>(); this.columnDataCash = new HashMap<String, Map<String, ColumnData>>(); this.tableForeignKeyDataMap = new HashMap<String, List<ForeignKeyData>>(); this.dictionary = new HashMap<UniqueWord, Word>(); } public void init(Connection con, DBSetting dbSetting, ERDiagram diagram, List<DBObject> dbObjectList, boolean useCommentAsLogicalName, boolean mergeWord) throws SQLException { this.con = con; this.dbSetting = dbSetting; this.diagram = diagram; this.dbObjectList = dbObjectList; this.useCommentAsLogicalName = useCommentAsLogicalName; this.mergeWord = mergeWord; this.metaData = con.getMetaData(); this.translationResources = new TranslationResources(diagram .getDiagramContents().getSettings().getTranslationSetting()); if (this.mergeWord) { for (Word word : this.diagram.getDiagramContents().getDictionary() .getWordList()) { this.dictionary.put(new UniqueWord(word), word); } } } public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { monitor.beginTask(ResourceString .getResourceString("dialog.message.import.table"), this.dbObjectList.size()); this.importedSequences = this.importSequences(this.dbObjectList); this.importedTriggers = this.importTriggers(this.dbObjectList); this.importedTablespaces = this .importTablespaces(this.dbObjectList); this.importedTables = this.importTables(this.dbObjectList, monitor); this.importedTables.addAll(this.importSynonyms()); this.setForeignKeys(this.importedTables); this.importedViews = this.importViews(this.dbObjectList); } catch (InterruptedException e) { throw e; } catch (Exception e) { logger.log(Level.WARNING, e.getMessage(), e); this.exception = e; } monitor.done(); } protected void cashColumnData(List<DBObject> dbObjectList, IProgressMonitor monitor) throws SQLException, InterruptedException { this.cashColumnDataX(null, dbObjectList, monitor); } protected void cashColumnDataX(String tableName, List<DBObject> dbObjectList, IProgressMonitor monitor) throws SQLException, InterruptedException { ResultSet columnSet = null; try { columnSet = metaData.getColumns(null, null, tableName, null); while (columnSet.next()) { tableName = columnSet.getString("TABLE_NAME"); String schema = columnSet.getString("TABLE_SCHEM"); String tableNameWithSchema = this.dbSetting .getTableNameWithSchema(tableName, schema); if (monitor != null) { monitor.subTask("reading : " + tableNameWithSchema); } Map<String, ColumnData> cash = this.columnDataCash .get(tableNameWithSchema); if (cash == null) { cash = new LinkedHashMap<String, ColumnData>(); this.columnDataCash.put(tableNameWithSchema, cash); } ColumnData columnData = this.createColumnData(columnSet); this.cashOtherColumnData(tableName, schema, columnData); cash.put(columnData.columnName, columnData); if (monitor != null && monitor.isCanceled()) { throw new InterruptedException("Cancel has been requested."); } } } finally { if (columnSet != null) { columnSet.close(); } } } protected ColumnData createColumnData(ResultSet columnSet) throws SQLException { ColumnData columnData = new ColumnData(); columnData.columnName = columnSet.getString("COLUMN_NAME"); columnData.type = columnSet.getString("TYPE_NAME").toLowerCase(); columnData.size = columnSet.getInt("COLUMN_SIZE"); columnData.decimalDegits = columnSet.getInt("DECIMAL_DIGITS"); columnData.nullable = columnSet.getInt("NULLABLE"); columnData.defaultValue = columnSet.getString("COLUMN_DEF"); if (columnData.defaultValue != null) { if ("bit".equals(columnData.type)) { byte[] bits = columnData.defaultValue.getBytes(); columnData.defaultValue = ""; for (int i = 0; i < bits.length; i++) { columnData.defaultValue += bits[i]; } } } columnData.description = columnSet.getString("REMARKS"); return columnData; } protected void cashOtherColumnData(String tableName, String schema, ColumnData columnData) throws SQLException { } protected void cashTableComment(IProgressMonitor monitor) throws SQLException, InterruptedException { } private List<Sequence> importSequences(List<DBObject> dbObjectList) throws SQLException { List<Sequence> list = new ArrayList<Sequence>(); for (DBObject dbObject : dbObjectList) { if (DBObject.TYPE_SEQUENCE.equals(dbObject.getType())) { String schema = dbObject.getSchema(); String name = dbObject.getName(); Sequence sequence = this.importSequence(schema, name); if (sequence != null) { list.add(sequence); } } } return list; } protected Sequence importSequence(String schema, String sequenceName) throws SQLException { PreparedStatement stmt = null; ResultSet rs = null; String sequenceNameWithSchema = this.getTableNameWithSchema(schema, sequenceName); try { stmt = this.con.prepareStatement("SELECT * FROM " + sequenceNameWithSchema); rs = stmt.executeQuery(); if (rs.next()) { Sequence sequence = new Sequence(); sequence.setName(sequenceName); sequence.setSchema(schema); sequence.setIncrement(rs.getInt("INCREMENT_BY")); sequence.setMinValue(rs.getLong("MIN_VALUE")); BigDecimal maxValue = rs.getBigDecimal("MAX_VALUE"); sequence.setMaxValue(maxValue); sequence.setStart(rs.getLong("LAST_VALUE")); sequence.setCache(rs.getInt("CACHE_VALUE")); sequence.setCycle(rs.getBoolean("IS_CYCLED")); return sequence; } return null; } finally { this.close(rs); this.close(stmt); } } private List<Trigger> importTriggers(List<DBObject> dbObjectList) throws SQLException { List<Trigger> list = new ArrayList<Trigger>(); for (DBObject dbObject : dbObjectList) { if (DBObject.TYPE_TRIGGER.equals(dbObject.getType())) { String schema = dbObject.getSchema(); String name = dbObject.getName(); Trigger trigger = this.importTrigger(schema, name); if (trigger != null) { list.add(trigger); } } } return list; } protected Trigger importTrigger(String schema, String triggerName) throws SQLException { // return null; } protected List<ERTable> importTables(List<DBObject> dbObjectList, IProgressMonitor monitor) throws SQLException, InterruptedException { List<ERTable> list = new ArrayList<ERTable>(); this.cashTableComment(monitor); this.cashColumnData(dbObjectList, monitor); int i = 0; for (DBObject dbObject : dbObjectList) { if (DBObject.TYPE_TABLE.equals(dbObject.getType())) { i++; String tableName = dbObject.getName(); String schema = dbObject.getSchema(); String tableNameWithSchema = this.dbSetting .getTableNameWithSchema(tableName, schema); monitor.subTask("(" + i + "/" + this.dbObjectList.size() + ") " + tableNameWithSchema); monitor.worked(1); ERTable table = this.importTable(tableNameWithSchema, tableName, schema); if (table != null) { list.add(table); } } if (monitor.isCanceled()) { throw new InterruptedException("Cancel has been requested."); } } return list; } protected List<ERTable> importSynonyms() throws SQLException, InterruptedException { return new ArrayList<ERTable>(); } protected String getConstraintName(PrimaryKeyData data) { return data.constraintName; } protected ERTable importTable(String tableNameWithSchema, String tableName, String schema) throws SQLException, InterruptedException { String autoIncrementColumnName = null; try { autoIncrementColumnName = this.getAutoIncrementColumnName(con, this.getTableNameWithSchema(schema, tableName)); } catch (SQLException e) { // �スe�ス[�スu�ス�ス�ス�スェ取得�スナゑソス�スネゑソス�ス鼾�ソスi�ス�ス�スフ�ソス�ス[�スU�スフ擾ソス�スL�ス�ス�スネどの場合�スj�スA // �ス�ス�スフテ�ス[�スu�ス�ス�スヘ使�スp�ス�ス�スネゑソス�スB return null; } ERTable table = new ERTable(); TableViewProperties tableProperties = table .getTableViewProperties(this.dbSetting.getDbsystem()); tableProperties.setSchema(schema); table.setPhysicalName(tableName); table.setLogicalName(this.translationResources.translate(tableName)); table.setDescription(this.tableCommentMap.get(tableNameWithSchema)); List<PrimaryKeyData> primaryKeys = this.getPrimaryKeys(table, this.metaData); if (!primaryKeys.isEmpty()) { table.setPrimaryKeyName(getConstraintName(primaryKeys.get(0))); } List<Index> indexes = this .getIndexes(table, this.metaData, primaryKeys); List<Column> columns = this.getColumns(tableNameWithSchema, tableName, schema, indexes, primaryKeys, autoIncrementColumnName); table.setColumns(columns); table.setIndexes(indexes); this.tableMap.put(tableNameWithSchema, table); for (Index index : indexes) { this.setIndexColumn(table, index); } return table; } protected String getTableNameWithSchema(String schema, String tableName) { return this.dbSetting.getTableNameWithSchema(tableName, schema); } protected void setForeignKeys(List<ERTable> list) throws SQLException { this.cashForeignKeyData(); for (ERTable target : list) { if (this.tableForeignKeyDataMap != null) { this.setForeignKeysUsingCash(target); } else { this.setForeignKeys(target); } } } private String getAutoIncrementColumnName(Connection con, String tableNameWithSchema) throws SQLException { String autoIncrementColumnName = null; Statement stmt = null; ResultSet rs = null; try { stmt = con.createStatement(); rs = stmt.executeQuery("SELECT * FROM " + tableNameWithSchema); ResultSetMetaData md = rs.getMetaData(); for (int i = 0; i < md.getColumnCount(); i++) { if (md.isAutoIncrement(i + 1)) { autoIncrementColumnName = md.getColumnName(i + 1); break; } } } finally { this.close(rs); this.close(stmt); } return autoIncrementColumnName; } protected List<Index> getIndexes(ERTable table, DatabaseMetaData metaData, List<PrimaryKeyData> primaryKeys) throws SQLException { List<Index> indexes = new ArrayList<Index>(); Map<String, Index> indexMap = new HashMap<String, Index>(); ResultSet indexSet = null; try { // getIndexInfo �ス�ス table �スw�ス�スネゑソス�スナは取得�スナゑソス�スネゑソス�ス�ス�ス゚、 // �スe�ス[�スu�ス�ス�ス�ス�スニに取得�ス�ス�ス�スK�スv�ス�ス�ス�ス�ス�スワゑソス�スB indexSet = metaData.getIndexInfo(null, table .getTableViewProperties(this.dbSetting.getDbsystem()) .getSchema(), table.getPhysicalName(), false, true); while (indexSet.next()) { String name = indexSet.getString("INDEX_NAME"); if (name == null) { continue; } Index index = indexMap.get(name); if (index == null) { boolean nonUnique = indexSet.getBoolean("NON_UNIQUE"); String type = null; short indexType = indexSet.getShort("TYPE"); if (indexType == DatabaseMetaData.tableIndexOther) { type = "BTREE"; } // DatabaseMetaData.tableIndexClustered // DatabaseMetaData.tableIndexOther // DatabaseMetaData.tableIndexStatistic index = new Index(table, name, nonUnique, type, null); indexMap.put(name, index); indexes.add(index); } String columnName = indexSet.getString("COLUMN_NAME"); String ascDesc = indexSet.getString("ASC_OR_DESC"); if (columnName.startsWith("\"") && columnName.endsWith("\"")) { columnName = columnName.substring(1, columnName.length() - 1); } Boolean desc = null; if ("A".equals(ascDesc)) { desc = Boolean.FALSE; } else if ("D".equals(ascDesc)) { desc = Boolean.TRUE; } index.addColumnName(columnName, desc); } } catch (SQLException e) { throw e; } finally { this.close(indexSet); } for (Iterator<Index> iter = indexes.iterator(); iter.hasNext();) { Index index = iter.next(); List<String> indexColumns = index.getColumnNames(); if (indexColumns.size() == primaryKeys.size()) { boolean equals = true; for (int i = 0; i < indexColumns.size(); i++) { if (!indexColumns.get(i).equals( primaryKeys.get(i).columnName)) { equals = false; break; } } if (equals) { iter.remove(); } } } return indexes; } private void setIndexColumn(ERTable erTable, Index index) { for (String columnName : index.getColumnNames()) { for (Column column : erTable.getColumns()) { if (column instanceof NormalColumn) { NormalColumn normalColumn = (NormalColumn) column; if (normalColumn.getPhysicalName().equals(columnName)) { index.addColumn(normalColumn); break; } } } } } private List<PrimaryKeyData> getPrimaryKeys(ERTable table, DatabaseMetaData metaData) throws SQLException { List<PrimaryKeyData> primaryKeys = new ArrayList<PrimaryKeyData>(); ResultSet primaryKeySet = null; try { primaryKeySet = metaData.getPrimaryKeys(null, table .getTableViewProperties(this.dbSetting.getDbsystem()) .getSchema(), table.getPhysicalName()); while (primaryKeySet.next()) { PrimaryKeyData data = new PrimaryKeyData(); data.columnName = primaryKeySet.getString("COLUMN_NAME"); data.constraintName = primaryKeySet.getString("PK_NAME"); primaryKeys.add(data); } } catch (SQLException e) { // Microsoft Access does not support getPrimaryKeys } finally { this.close(primaryKeySet); } return primaryKeys; } protected Map<String, ColumnData> getColumnDataMap( String tableNameWithSchema, String tableName, String schema) throws SQLException, InterruptedException { return this.columnDataCash.get(tableNameWithSchema); } private List<Column> getColumns(String tableNameWithSchema, String tableName, String schema, List<Index> indexes, List<PrimaryKeyData> primaryKeys, String autoIncrementColumnName) throws SQLException, InterruptedException { List<Column> columns = new ArrayList<Column>(); Map<String, ColumnData> columnDataMap = this.getColumnDataMap( tableNameWithSchema, tableName, schema); if (columnDataMap == null) { return new ArrayList<Column>(); } Collection<ColumnData> columnSet = columnDataMap.values(); for (ColumnData columnData : columnSet) { String columnName = columnData.columnName; String type = columnData.type; boolean array = false; Integer arrayDimension = null; boolean unsigned = false; int unsignedIndex = type.indexOf(" UNSIGNED"); if (unsignedIndex != -1) { unsigned = true; type = type.substring(0, unsignedIndex); } int arrayStartIndex = type.indexOf("["); if (arrayStartIndex != -1) { array = true; String str = type.substring(arrayStartIndex + 1, type.indexOf("]")); arrayDimension = Integer.parseInt(str); type = type.substring(0, arrayStartIndex); } int size = this.getLength(type, columnData.size); Integer length = new Integer(size); SqlType sqlType = SqlType.valueOf(this.dbSetting.getDbsystem(), type, size); if (sqlType == null || LOG_SQL_TYPE) { logger.info(columnName + ": " + type + ", " + size + ", " + columnData.decimalDegits); } int decimalDegits = columnData.decimalDegits; Integer decimal = new Integer(decimalDegits); boolean notNull = false; if (columnData.nullable == DatabaseMetaData.columnNoNulls) { notNull = true; } String defaultValue = Format.null2blank(columnData.defaultValue); if (sqlType != null) { if (SqlType.SQL_TYPE_ID_SERIAL.equals(sqlType.getId()) || SqlType.SQL_TYPE_ID_BIG_SERIAL.equals(sqlType .getId())) { defaultValue = ""; } } String description = Format.null2blank(columnData.description); String constraint = Format.null2blank(columnData.constraint); boolean primaryKey = false; for (PrimaryKeyData primaryKeyData : primaryKeys) { if (columnName.equals(primaryKeyData.columnName)) { primaryKey = true; break; } } boolean uniqueKey = this.isUniqueKey(columnName, indexes, primaryKeys); boolean autoIncrement = columnName .equalsIgnoreCase(autoIncrementColumnName); String logicalName = null; //description = ID:ID if (this.useCommentAsLogicalName && !Check.isEmpty(description)) { int pos = description.indexOf(':'); if (pos >= 0) { logicalName = description.substring(0, pos).replaceAll("[\r\n]", ""); description = description.substring(pos + 1); } else { logicalName = description.replaceAll("[\r\n]", ""); } } if (Check.isEmpty(logicalName)) { logicalName = this.translationResources.translate(columnName); } String args = columnData.enumData; TypeData typeData = new TypeData(length, decimal, array, arrayDimension, unsigned, args); Word word = new Word(columnName, logicalName, sqlType, typeData, description, this.diagram.getDatabase()); UniqueWord uniqueWord = new UniqueWord(word); if (this.dictionary.get(uniqueWord) != null) { word = this.dictionary.get(uniqueWord); } else { this.dictionary.put(uniqueWord, word); } // TODO UNIQUE KEY �スフ撰ソス�スシゑソス�ス謫セ�スナゑソス�ストゑソス�スネゑソス NormalColumn column = new NormalColumn(word, notNull, primaryKey, uniqueKey, autoIncrement, defaultValue, constraint, null, null, null); columns.add(column); } return columns; } private boolean isUniqueKey(String columnName, List<Index> indexes, List<PrimaryKeyData> primaryKeys) { String primaryKey = null; if (primaryKeys.size() == 1) { primaryKey = primaryKeys.get(0).columnName; } if (columnName == null) { return false; } for (Index index : indexes) { List<String> columnNames = index.getColumnNames(); if (columnNames.size() == 1) { String indexColumnName = columnNames.get(0); if (columnName.equals(indexColumnName)) { if (!index.isNonUnique()) { if (!columnName.equals(primaryKey)) { indexes.remove(index); return true; } return false; } } } } return false; } private boolean isCyclicForeignKye(ForeignKeyData foreignKeyData) { if (foreignKeyData.sourceSchemaName == null) { if (foreignKeyData.targetSchemaName != null) { return false; } } else if (!foreignKeyData.sourceSchemaName .equals(foreignKeyData.targetSchemaName)) { return false; } if (!foreignKeyData.sourceTableName .equals(foreignKeyData.targetTableName)) { return false; } if (!foreignKeyData.sourceColumnName .equals(foreignKeyData.targetColumnName)) { return false; } return true; } private void cashForeignKeyData() throws SQLException { ResultSet foreignKeySet = null; try { foreignKeySet = metaData.getImportedKeys(null, null, null); while (foreignKeySet.next()) { ForeignKeyData foreignKeyData = new ForeignKeyData(); foreignKeyData.name = foreignKeySet.getString("FK_NAME"); foreignKeyData.sourceSchemaName = foreignKeySet .getString("PKTABLE_SCHEM"); foreignKeyData.sourceTableName = foreignKeySet .getString("PKTABLE_NAME"); foreignKeyData.sourceColumnName = foreignKeySet .getString("PKCOLUMN_NAME"); foreignKeyData.targetSchemaName = foreignKeySet .getString("FKTABLE_SCHEM"); foreignKeyData.targetTableName = foreignKeySet .getString("FKTABLE_NAME"); foreignKeyData.targetColumnName = foreignKeySet .getString("FKCOLUMN_NAME"); foreignKeyData.updateRule = foreignKeySet .getShort("UPDATE_RULE"); foreignKeyData.deleteRule = foreignKeySet .getShort("DELETE_RULE"); if (this.isCyclicForeignKye(foreignKeyData)) { continue; } String key = this.dbSetting.getTableNameWithSchema( foreignKeyData.targetTableName, foreignKeyData.targetSchemaName); List<ForeignKeyData> foreignKeyDataList = tableForeignKeyDataMap .get(key); if (foreignKeyDataList == null) { foreignKeyDataList = new ArrayList<ForeignKeyData>(); tableForeignKeyDataMap.put(key, foreignKeyDataList); } foreignKeyDataList.add(foreignKeyData); } } catch (SQLException e) { tableForeignKeyDataMap = null; } finally { this.close(foreignKeySet); } } private void setForeignKeysUsingCash(ERTable target) throws SQLException { String tableName = target.getPhysicalName(); String schema = target.getTableViewProperties( this.dbSetting.getDbsystem()).getSchema(); tableName = this.dbSetting.getTableNameWithSchema(tableName, schema); List<ForeignKeyData> foreignKeyList = this.tableForeignKeyDataMap .get(tableName); if (foreignKeyList == null) { return; } Map<String, List<ForeignKeyData>> sameNameForeignKeyDataMap = this .collectSameNameForeignKeyData(foreignKeyList); for (Map.Entry<String, List<ForeignKeyData>> entry : sameNameForeignKeyDataMap .entrySet()) { this.createRelation(target, entry.getValue()); } } private void setForeignKeys(ERTable target) throws SQLException { String tableName = target.getPhysicalName(); String schemaName = target.getTableViewProperties( this.dbSetting.getDbsystem()).getSchema(); ResultSet foreignKeySet = null; try { foreignKeySet = this.metaData.getImportedKeys(null, schemaName, tableName); List<ForeignKeyData> foreignKeyList = new ArrayList<ForeignKeyData>(); while (foreignKeySet.next()) { ForeignKeyData foreignKeyData = new ForeignKeyData(); foreignKeyData.name = foreignKeySet.getString("FK_NAME"); foreignKeyData.sourceTableName = foreignKeySet .getString("PKTABLE_NAME"); foreignKeyData.sourceSchemaName = foreignKeySet .getString("PKTABLE_SCHEM"); foreignKeyData.sourceColumnName = foreignKeySet .getString("PKCOLUMN_NAME"); foreignKeyData.targetSchemaName = foreignKeySet .getString("FKTABLE_SCHEM"); foreignKeyData.targetColumnName = foreignKeySet .getString("FKCOLUMN_NAME"); foreignKeyData.updateRule = foreignKeySet .getShort("UPDATE_RULE"); foreignKeyData.deleteRule = foreignKeySet .getShort("DELETE_RULE"); foreignKeyList.add(foreignKeyData); } if (foreignKeyList.isEmpty()) { return; } Map<String, List<ForeignKeyData>> sameNameForeignKeyDataMap = this .collectSameNameForeignKeyData(foreignKeyList); for (Map.Entry<String, List<ForeignKeyData>> entry : sameNameForeignKeyDataMap .entrySet()) { this.createRelation(target, entry.getValue()); } } catch (SQLException e) { // microsoft access does not support getImportedKeys } finally { this.close(foreignKeySet); } } private Map<String, List<ForeignKeyData>> collectSameNameForeignKeyData( List<ForeignKeyData> foreignKeyList) { Map<String, List<ForeignKeyData>> map = new HashMap<String, List<ForeignKeyData>>(); for (ForeignKeyData foreignKyeData : foreignKeyList) { List<ForeignKeyData> list = map.get(foreignKyeData.name); if (list == null) { list = new ArrayList<ForeignKeyData>(); map.put(foreignKyeData.name, list); } list.add(foreignKyeData); } return map; } private Relation createRelation(ERTable target, List<ForeignKeyData> foreignKeyDataList) { ForeignKeyData representativeData = foreignKeyDataList.get(0); String sourceTableName = representativeData.sourceTableName; String sourceSchemaName = representativeData.sourceSchemaName; sourceTableName = this.dbSetting.getTableNameWithSchema( sourceTableName, sourceSchemaName); ERTable source = this.tableMap.get(sourceTableName); if (source == null) { return null; } boolean referenceForPK = true; List<NormalColumn> primaryKeys = source.getPrimaryKeys(); if (primaryKeys.size() != foreignKeyDataList.size()) { referenceForPK = false; } Map<NormalColumn, NormalColumn> referenceMap = new HashMap<NormalColumn, NormalColumn>(); for (ForeignKeyData foreignKeyData : foreignKeyDataList) { NormalColumn sourceColumn = null; for (NormalColumn normalColumn : source.getNormalColumns()) { if (normalColumn.getPhysicalName().equals( foreignKeyData.sourceColumnName)) { sourceColumn = normalColumn; break; } } if (sourceColumn == null) { return null; } if (!sourceColumn.isPrimaryKey()) { referenceForPK = false; } NormalColumn targetColumn = null; for (NormalColumn normalColumn : target.getNormalColumns()) { if (normalColumn.getPhysicalName().equals( foreignKeyData.targetColumnName)) { targetColumn = normalColumn; break; } } if (targetColumn == null) { return null; } referenceMap.put(sourceColumn, targetColumn); } ComplexUniqueKey referencedComplexUniqueKey = null; NormalColumn referencedColumn = null; if (!referenceForPK) { if (referenceMap.size() > 1) { // TODO �ス�ス�ス�ス�ス�スモキ�ス[�スフ撰ソス�スシを復鯉ソス�スナゑソス�ストゑソス�スネゑソス referencedComplexUniqueKey = new ComplexUniqueKey(""); for (NormalColumn column : referenceMap.keySet()) { referencedComplexUniqueKey.addColumn(column); } // TODO �ス�ス�ス�ス�スナ包ソス�ス�ス�ス�スモキ�ス[�ス�スヌ隠�ス�ス�スフではなゑソス�スAindex // �ス�ス�ス辜�ソスj�ス[�スN�スL�ス[�ス�ス�ス�スニゑソス�ス�スナゑソス�ス�スH source.getComplexUniqueKeyList() .add(referencedComplexUniqueKey); } else { referencedColumn = referenceMap.keySet().iterator().next(); } } Relation relation = new Relation(referenceForPK, referencedComplexUniqueKey, referencedColumn); relation.setName(representativeData.name); relation.setSource(source); relation.setTargetWithoutForeignKey(target); String onUpdateAction = null; if (representativeData.updateRule == DatabaseMetaData.importedKeyCascade) { onUpdateAction = "CASCADE"; } else if (representativeData.updateRule == DatabaseMetaData.importedKeyRestrict) { onUpdateAction = "RESTRICT"; } else if (representativeData.updateRule == DatabaseMetaData.importedKeyNoAction) { onUpdateAction = "NO ACTION"; } else if (representativeData.updateRule == DatabaseMetaData.importedKeySetDefault) { onUpdateAction = "SET DEFAULT"; } else if (representativeData.updateRule == DatabaseMetaData.importedKeySetNull) { onUpdateAction = "SET NULL"; } else { onUpdateAction = ""; } relation.setOnUpdateAction(onUpdateAction); String onDeleteAction = null; if (representativeData.deleteRule == DatabaseMetaData.importedKeyCascade) { onDeleteAction = "CASCADE"; } else if (representativeData.deleteRule == DatabaseMetaData.importedKeyRestrict) { onDeleteAction = "RESTRICT"; } else if (representativeData.deleteRule == DatabaseMetaData.importedKeyNoAction) { onDeleteAction = "NO ACTION"; } else if (representativeData.deleteRule == DatabaseMetaData.importedKeySetDefault) { onDeleteAction = "SET DEFAULT"; } else if (representativeData.deleteRule == DatabaseMetaData.importedKeySetNull) { onDeleteAction = "SET NULL"; } else { onDeleteAction = ""; } relation.setOnDeleteAction(onDeleteAction); for (Map.Entry<NormalColumn, NormalColumn> entry : referenceMap .entrySet()) { entry.getValue().addReference(entry.getKey(), relation); } return relation; } public List<ERTable> getImportedTables() { return importedTables; } public List<Sequence> getImportedSequences() { return importedSequences; } public List<View> getImportedViews() { return importedViews; } private List<View> importViews(List<DBObject> dbObjectList) throws SQLException { List<View> list = new ArrayList<View>(); for (DBObject dbObject : dbObjectList) { if (DBObject.TYPE_VIEW.equals(dbObject.getType())) { String schema = dbObject.getSchema(); String name = dbObject.getName(); View view = this.importView(schema, name); if (view != null) { list.add(view); } } } return list; } protected View importView(String schema, String viewName) throws SQLException { PreparedStatement stmt = null; ResultSet rs = null; String sql = getViewDefinitionSQL(schema); if (sql == null) { return null; } try { stmt = this.con.prepareStatement(sql); if (schema != null) { stmt.setString(1, schema); stmt.setString(2, viewName); } else { stmt.setString(1, viewName); } rs = stmt.executeQuery(); if (rs.next()) { View view = new View(); view.setPhysicalName(viewName); view.setLogicalName(this.translationResources .translate(viewName)); String definitionSQL = rs.getString(1); view.setSql(definitionSQL); view.getTableViewProperties().setSchema(schema); List<Column> columnList = this.getViewColumnList(definitionSQL); view.setColumns(columnList); return view; } return null; } finally { this.close(rs); this.close(stmt); } } protected abstract String getViewDefinitionSQL(String schema); private List<Column> getViewColumnList(String sql) { List<Column> columnList = new ArrayList<Column>(); String upperSql = sql.toUpperCase(); int selectIndex = upperSql.indexOf("SELECT "); int fromIndex = upperSql.indexOf(" FROM "); if (selectIndex == -1) { return null; } String columnsPart = null; String fromPart = null; if (fromIndex != -1) { columnsPart = sql.substring(selectIndex + "SELECT ".length(), fromIndex); fromPart = sql.substring(fromIndex + " FROM ".length()); } else { columnsPart = sql.substring(selectIndex + "SELECT ".length()); fromPart = ""; } int whereIndex = fromPart.toUpperCase().indexOf(" WHERE "); if (whereIndex != -1) { fromPart = fromPart.substring(0, whereIndex); } Map<String, String> aliasTableMap = new HashMap<String, String>(); StringTokenizer fromTokenizer = new StringTokenizer(fromPart, ","); while (fromTokenizer.hasMoreTokens()) { String tableName = fromTokenizer.nextToken().trim(); tableName.replaceAll(" AS", ""); tableName.replaceAll(" as", ""); tableName.replaceAll(" As", ""); tableName.replaceAll(" aS", ""); String tableAlias = null; int asIndex = tableName.toUpperCase().indexOf(" "); if (asIndex != -1) { tableAlias = tableName.substring(asIndex + 1).trim(); tableName = tableName.substring(0, asIndex).trim(); // schema.tablename �スフ場合�スAschema �スウ趣ソス�ス�ス�スト考�ス�ス�ス�ス // TODO schema �ス�スl�ス�ス�ス�ス�スト考�ス�ス�ス�ス�ス�ス謔「 int dotIndex = tableName.indexOf("."); if (dotIndex != -1) { tableName = tableName.substring(dotIndex + 1); } aliasTableMap.put(tableAlias, tableName); } } StringTokenizer columnTokenizer = new StringTokenizer(columnsPart, ","); String previousColumn = null; while (columnTokenizer.hasMoreTokens()) { String columnName = columnTokenizer.nextToken(); if (previousColumn != null) { columnName = previousColumn + "," + columnName; previousColumn = null; } if (columnName.split("\\(").length > columnName.split("\\)").length) { previousColumn = columnName; continue; } columnName = columnName.trim(); columnName = columnName.replaceAll("\"", ""); String columnAlias = null; Matcher matcher = AS_PATTERN.matcher(columnName); if (matcher.matches()) { columnAlias = matcher.toMatchResult().group(2).trim(); columnName = matcher.toMatchResult().group(1).trim(); } else { int asIndex = columnName.indexOf(" "); if (asIndex != -1) { columnAlias = columnName.substring(asIndex + 1).trim(); columnName = columnName.substring(0, asIndex).trim(); } } int dotIndex = columnName.indexOf("."); String tableName = null; if (dotIndex != -1) { String aliasTableName = columnName.substring(0, dotIndex); columnName = columnName.substring(dotIndex + 1); // schema.tablename.columnname �スフ場合 dotIndex = columnName.indexOf("."); if (dotIndex != -1) { aliasTableName = columnName.substring(0, dotIndex); columnName = columnName.substring(dotIndex + 1); } tableName = aliasTableMap.get(aliasTableName); if (tableName == null) { tableName = aliasTableName; } } if (columnAlias == null) { columnAlias = columnName; } NormalColumn targetColumn = null; if (columnName != null) { if (tableName != null) { tableName = tableName.toLowerCase(); } columnName = columnName.toLowerCase(); if (!"*".equals(columnName)) { for (ERTable table : this.importedTables) { if (tableName == null || (table.getPhysicalName() != null && tableName .equals(table.getPhysicalName() .toLowerCase()))) { for (NormalColumn column : table .getExpandedColumns()) { if (column.getPhysicalName() != null && columnName.equals(column .getPhysicalName() .toLowerCase())) { targetColumn = column; break; } } if (targetColumn != null) { break; } } } this.addColumnToView(columnList, targetColumn, columnAlias); } else { for (ERTable table : this.importedTables) { if (tableName == null || (table.getPhysicalName() != null && tableName .equals(table.getPhysicalName() .toLowerCase()))) { for (NormalColumn column : table .getExpandedColumns()) { this.addColumnToView(columnList, column, null); } } } } } } return columnList; } private void addColumnToView(List<Column> columnList, NormalColumn targetColumn, String columnAlias) { Word word = null; if (targetColumn != null) { word = new Word(targetColumn.getWord()); if (columnAlias != null) { word.setPhysicalName(columnAlias); } } else { word = new Word(columnAlias, this.translationResources.translate(columnAlias), null, new TypeData(null, null, false, null, false, null), null, null); } UniqueWord uniqueWord = new UniqueWord(word); if (this.dictionary.get(uniqueWord) != null) { word = this.dictionary.get(uniqueWord); } else { this.dictionary.put(uniqueWord, word); } NormalColumn column = new NormalColumn(word, false, false, false, false, null, null, null, null, null); columnList.add(column); } public List<Tablespace> getImportedTablespaces() { return importedTablespaces; } private List<Tablespace> importTablespaces(List<DBObject> dbObjectList) throws SQLException { List<Tablespace> list = new ArrayList<Tablespace>(); for (DBObject dbObject : dbObjectList) { if (DBObject.TYPE_TABLESPACE.equals(dbObject.getType())) { String name = dbObject.getName(); Tablespace tablespace = this.importTablespace(name); if (tablespace != null) { list.add(tablespace); } } } return list; } public List<Trigger> getImportedTriggers() { return importedTriggers; } protected Tablespace importTablespace(String tablespaceName) throws SQLException { // TODO �スe�ス[�スu�ス�ス�スX�スy�ス[�スX�スフイ�ス�ス�ス|�ス[�スg return null; } public Exception getException() { return exception; } protected int getLength(String type, int size) { return size; } public static void main(String[] args) throws InputException, InstantiationException, IllegalAccessException, SQLException { new Activator(); DBSetting setting = new DBSetting("Oracle", "localhost", 1521, "XE", "nakajima", "nakajima", true, null, null); Connection con = null; try { con = setting.connect(); DatabaseMetaData metaData = con.getMetaData(); metaData.getIndexInfo(null, "SYS", "ALERT_QT", false, false); } finally { if (con != null) { con.close(); } } } protected void close(ResultSet rs) throws SQLException { if (rs != null) { rs.close(); } } protected void close(Statement stmt) throws SQLException { if (stmt != null) { stmt.close(); } } }