/** @return */ public ResolverResult sortTables() { final LinkedHashMap<String, Table> resolved = new LinkedHashMap<String, Table>(); Map<String, Table> unresolved = null; // first run: separate tables with and without dependencies while (_tableIter.hasNext()) { final Table t = _tableIter.next(); if (t == null) { continue; } final Set<ColumnFkInfo> fks = t.getForeignKeys(); // no dependency / foreign key? Logger.debug("[sortTables] put %s to resolved.", t); if (fks == null) { resolved.put(t.getName(), t); } else { // dependency fulfilled? boolean nodep = true; final Iterator<ColumnFkInfo> iter2 = fks.iterator(); while (iter2.hasNext() && nodep) { final ColumnFkInfo fk = iter2.next(); if (!resolved.containsKey(fk.getPkTable())) { nodep = false; } } if (nodep) { resolved.put(t.getName(), t); } else { if (unresolved == null) { unresolved = new HashMap<String, Table>(); } unresolved.put(t.getName(), t); } } } // second run: we check remaining deps if (unresolved != null) { for (Table t : unresolved.values()) { resolveDep(t, null, resolved, unresolved); } } // do we need a second run? // unresolved = cleanUnresolved( resolved, unresolved ); // add all unresolved/conflicting tables to the resulting list final Collection<Table> result = resolved.values(); if (unresolved != null) { for (Table table : unresolved.values()) { if (!result.contains(table)) { result.add(table); } } } return new ResolverResult(result, _cyclicDependencies); }
private static void appendModified( final List<Column[]> rows, final LinkedHashMap<henplus.sqlmodel.Column, henplus.sqlmodel.Column> modified) { final Iterator<henplus.sqlmodel.Column> iter = modified.keySet().iterator(); while (iter.hasNext()) { final henplus.sqlmodel.Column org = iter.next(); final henplus.sqlmodel.Column mod = modified.get(org); final ExtendedColumn[] orgView = new ExtendedColumn[8]; final ExtendedColumn[] modView = new ExtendedColumn[8]; orgView[0] = new ExtendedColumn(STAT_MODIFIED_ORG, DESC_META[0].getAlignment()); modView[0] = new ExtendedColumn(STAT_MODIFIED_NEW, DESC_META[0].getAlignment()); // if this was modified it doesn't matter orgView[1] = new ExtendedColumn(org.getPosition(), DESC_META[1].getAlignment()); modView[1] = new ExtendedColumn(mod.getPosition(), DESC_META[1].getAlignment()); // this should not differ orgView[2] = new ExtendedColumn(org.getName(), DESC_META[2].getAlignment()); modView[2] = new ExtendedColumn(mod.getName(), DESC_META[2].getAlignment()); final String orgType = extractType(org); final String modType = extractType(mod); orgView[3] = new ExtendedColumn(orgType, DESC_META[3].getAlignment()); modView[3] = new ExtendedColumn(modType, DESC_META[3].getAlignment()); if (!modType.equals(orgType)) { markAsChanged(modView[3]); } orgView[4] = new ExtendedColumn(org.isNullable() ? YES : NO, DESC_META[4].getAlignment()); modView[4] = new ExtendedColumn(mod.isNullable() ? YES : NO, DESC_META[4].getAlignment()); if (org.isNullable() != mod.isNullable()) { markAsChanged(modView[4]); } Logger.debug("default: %s", org.getDefault()); final String orgDefaultVal = org.getDefault() != null ? org.getDefault().trim() : null; // oracle appends newline to default values for some reason. orgView[5] = new ExtendedColumn(orgDefaultVal, DESC_META[5].getAlignment()); final String modDefaultVal = mod.getDefault() != null ? mod.getDefault().trim() : null; modView[5] = new ExtendedColumn(modDefaultVal, DESC_META[5].getAlignment()); if (orgDefaultVal != null && !orgDefaultVal.equals(modDefaultVal) || orgDefaultVal == null && modDefaultVal != null) { markAsChanged(modView[5]); } // primary key final String pkDescOrg = getPkDesc(org); final String pkDescMod = getPkDesc(mod); orgView[6] = new ExtendedColumn(pkDescOrg, DESC_META[6].getAlignment()); modView[6] = new ExtendedColumn(pkDescMod, DESC_META[6].getAlignment()); // check if one of the cols has to be marked as changed if (org.isPartOfPk() && !mod.isPartOfPk()) { markAsChanged(orgView[6]); } else if (!org.isPartOfPk() && mod.isPartOfPk()) { markAsChanged(modView[6]); } else if (org.isPartOfPk() && mod.isPartOfPk()) { // compare values of pk names if (org.getPkInfo().getPkName() != null && !org.getPkInfo().getPkName().equals(mod.getPkInfo().getPkName())) { markAsChanged(modView[6]); } } // foreign key final String fkDescOrg = getFkDesc(org); final String fkDescMod = getFkDesc(mod); orgView[7] = new ExtendedColumn(fkDescOrg, DESC_META[7].getAlignment()); modView[7] = new ExtendedColumn(fkDescMod, DESC_META[7].getAlignment()); // check if one of the cols has to be marked as changed if (org.isForeignKey() && !mod.isForeignKey()) { markAsChanged(orgView[7]); } else if (!org.isForeignKey() && mod.isForeignKey()) { markAsChanged(modView[7]); } else if (org.isForeignKey() && mod.isForeignKey()) { // compare values of pk names if (!org.getFkInfo().equals(mod.getFkInfo())) { markAsChanged(modView[7]); } } rows.add(orgView); rows.add(modView); } }
/** * @param t * @param cyclePath The path of tables which have cyclic dependencies * @param resolved * @param unresolved */ private void resolveDep( final Table t, List<Table> cyclePath, final Map<String, Table> resolved, final Map<String, Table> unresolved) { Logger.debug("[resolveDep] >>> Starting for t: %s and cyclePath: %s", t, cyclePath); // if the current table is no more in the unresolved collection if (t == null || resolved.containsKey(t.getName())) { return; } boolean nodep = false; boolean firstrun = true; final Set<ColumnFkInfo> fks = t.getForeignKeys(); final Iterator<ColumnFkInfo> iter = fks.iterator(); while (iter.hasNext()) { final ColumnFkInfo fk = iter.next(); Logger.debug( "[resolveDep] FK -> %s: %s", fk.getPkTable(), resolved.containsKey(fk.getPkTable())); if (!resolved.containsKey(fk.getPkTable())) { final Table inner = unresolved.get(fk.getPkTable()); // if there's yet a cycle with the two tables inner following t // then proceed to the next FK and ignore this potential cycle if (duplicateCycle(t, inner)) { continue; } if (cyclePath != null && cyclePath.contains(inner)) { cyclePath.add(t); // create a new list for the detected cycle to add to the // cyclicDeps, the former one (cyclePath) is used further on final List<Table> cycle = new ArrayList<Table>(cyclePath); cycle.add(inner); if (_cyclicDependencies == null) { _cyclicDependencies = new HashSet<List<Table>>(); } Logger.debug("[resolveDep] +++ Putting cyclePath: %s", cycle); _cyclicDependencies.add(cycle); continue; } else { if (cyclePath == null) { Logger.debug("[resolveDep] Starting cyclePath with: %s", t); cyclePath = new ArrayList<Table>(); } cyclePath.add(t); } resolveDep(inner, cyclePath, resolved, unresolved); if (resolved.containsKey(fk.getPkTable())) { nodep = (firstrun || nodep); firstrun = false; } } else { nodep = (firstrun || nodep); firstrun = false; } } if (nodep && !resolved.containsKey(t.getName())) { Logger.debug("[resolveDep] put %s to resolved.", t); resolved.put(t.getName(), t); } }