package com.med.sql; import java.io.PrintStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.sql.DataSource; import schemacrawler.schema.ForeignKey; import schemacrawler.schema.ForeignKeyColumnMap; import schemacrawler.schema.Schema; import schemacrawler.schema.Table; /** * This class generates lists of tables ordered by their foreign key dependencies. * * @author Jane Eisenstein * */ public class TableOrder { public List<Table> getTableDropOrder(List<Schema> schemas, PrintStream out) { List<Table> tables = getTableLoadOrder(schemas, out); List<Table> tableDropOrder = null; if (!tables.isEmpty()) { // flip table order by pushing contents onto a queue Table[] queue = new Table[tables.size()]; int i = queue.length - 1; for (Table table : tables) { queue[i--] = table; } // pop tables off queue into new list tableDropOrder = new ArrayList<Table>(tables.size()); for (Table table : queue) { tableDropOrder.add(table); } } return tableDropOrder; } public List<Table> getValuedTablesInOrder(DataSource ds, List<Table> tables, PrintStream out) { List<Table> valuedTables = new ArrayList<Table>(); Connection cn = null; try { cn = ds.getConnection(); for (Table table : tables) { String tableName = table.toString(); Statement stmt = null; ResultSet rs = null; int rowCount = -1; try { stmt = cn.createStatement(); rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName); // get the number of rows from the result set rs.next(); rowCount = rs.getInt(1); } catch ( Exception e ){ e.printStackTrace(); } finally { rs.close(); stmt.close(); } if (rowCount > 0) { valuedTables.add(table); if (out != null) out.println("Added valued table in load order: "+tableName); } } } catch (Exception e) { e.printStackTrace(); } finally { try { cn.close(); } catch (SQLException e) { } cn = null; } return valuedTables; } public List<Table> getTableLoadOrder(List<Schema> schemas, PrintStream out) { final List<Table> tables = new SchemaCrawlerUtils().getTableList(schemas); int tableCount = tables.size(); List<Table> tableLoadOrder = new ArrayList<Table>(tableCount); Set<Table> listedTables = new TreeSet<Table>(); Set<Table> fkTables = new TreeSet<Table>(); // add all tables with foreign keys to fkTables // add all other tables (those without foreign keys) to listedTables and tableLoadOrder for (Table table : tables) { final ForeignKey[] foreignKeys = table.getForeignKeys(); for (int j = 0; j < foreignKeys.length; j++) { final ForeignKey fk = foreignKeys[j]; ForeignKeyColumnMap[] cms = fk.getColumnPairs(); for (int k = 0; k < cms.length; k++) { ForeignKeyColumnMap cm = cms[k]; if (table.equals(cm.getForeignKeyColumn().getParent())) { fkTables.add(table); //if (out != null) out.println("\tTable "+table+" references another table."); break; } } } if (!fkTables.contains(table)) { // table has no foreign keys tableLoadOrder.add(table); listedTables.add(table); if (out != null) out.println("Added to list table with no fk: "+table); } } if (out != null) out.println("Number of tables with no fk = "+listedTables.size()); if (out != null) out.println("Number of tables with fk = "+fkTables.size()); if (out != null) out.println("Total number of tables = "+tableCount); int iteration = 0; while (listedTables.size() < tableCount) { iteration++; boolean addedTable = false; for (Table fkTable : fkTables) { if (!listedTables.contains(fkTable)) { // if all tables referenced by this table's foreign keys // have already been listed, add this table to the list as well boolean referencesUnlistedTable = false; final ForeignKey[] foreignKeys = fkTable.getForeignKeys(); for (int j = 0; j < foreignKeys.length; j++) { final ForeignKey fk = foreignKeys[j]; ForeignKeyColumnMap[] cms = fk.getColumnPairs(); for (int k = 0; k < cms.length; k++) { ForeignKeyColumnMap cm = cms[k]; if (fkTable.equals(cm.getForeignKeyColumn().getParent())) { Table pkTable = (Table) cm.getPrimaryKeyColumn().getParent(); if (!fkTable.equals(pkTable) && !listedTables.contains(pkTable) ) { referencesUnlistedTable = true; //if (out != null) out.println("\tTable "+table+" references an unlisted table."); break; } } } } if (!referencesUnlistedTable) { // table has no foreign keys to unlisted tables tableLoadOrder.add(fkTable); listedTables.add(fkTable); addedTable = true; if (out != null) out.println("Added to list table with fk: "+fkTable); } } } if (out != null) out.println("iteration: "+iteration); if (!addedTable) break; // there must be fk reference cycle in remaining tables } if (out != null) out.println("Processed a total of " + tableCount + " tables."); if (out != null) out.println("Returned list contains " + tableLoadOrder.size() + " tables."); if (tableLoadOrder.size() < tableCount) { for (Table fkTable : fkTables) { if (!listedTables.contains(fkTable)) { tableLoadOrder.add(fkTable); listedTables.add(fkTable); if (out != null) out.println("Added to list table with unresolved fk: "+fkTable); } } } if (out != null) out.println("Processed a total of " + tableCount + " tables."); if (out != null) out.println("Returned list contains " + tableLoadOrder.size() + " tables."); return tableLoadOrder; } }