db-ddlutils-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject svn commit: r602807 [5/15] - in /db/ddlutils/trunk: ./ src/java/org/apache/ddlutils/ src/java/org/apache/ddlutils/alteration/ src/java/org/apache/ddlutils/model/ src/java/org/apache/ddlutils/platform/ src/java/org/apache/ddlutils/platform/axion/ src/ja...
Date Mon, 10 Dec 2007 08:21:39 GMT
Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java Mon Dec 10 00:20:47 2007
@@ -19,9 +19,25 @@
  * under the License.
  */
 
+import java.io.IOException;
 import java.sql.Types;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
 
 import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.alteration.AddColumnChange;
+import org.apache.ddlutils.alteration.AddPrimaryKeyChange;
+import org.apache.ddlutils.alteration.ModelComparator;
+import org.apache.ddlutils.alteration.PrimaryKeyChange;
+import org.apache.ddlutils.alteration.RemoveColumnChange;
+import org.apache.ddlutils.alteration.TableChange;
+import org.apache.ddlutils.alteration.TableDefinitionChangesPredicate;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.platform.CreationParameters;
+import org.apache.ddlutils.platform.DefaultTableDefinitionChangesPredicate;
 import org.apache.ddlutils.platform.PlatformImplBase;
 
 /**
@@ -48,6 +64,7 @@
 
         info.setMaxIdentifierLength(31);
         info.setSystemForeignKeyIndicesAlwaysNonUnique(true);
+        info.setPrimaryKeyColumnAutomaticallyRequired(true);
         info.setCommentPrefix("/*");
         info.setCommentSuffix("*/");
 
@@ -87,5 +104,130 @@
     public String getName()
     {
         return DATABASENAME;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected ModelComparator getModelComparator()
+    {
+        ModelComparator comparator = super.getModelComparator();
+
+        comparator.setCanDropPrimaryKeyColumns(false);
+        return comparator;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected TableDefinitionChangesPredicate getTableDefinitionChangesPredicate()
+    {
+        return new DefaultTableDefinitionChangesPredicate()
+        {
+            public boolean areSupported(Table intermediateTable, List changes)
+            {
+                // Firebird does support adding a primary key, but only if none of the primary
+                // key columns have been added within the same session
+                if (super.areSupported(intermediateTable, changes))
+                {
+                    HashSet  addedColumns = new HashSet();
+                    String[] pkColNames   = null;
+
+                    for (Iterator it = changes.iterator(); it.hasNext();)
+                    {
+                        TableChange change = (TableChange)it.next();
+
+                        if (change instanceof AddColumnChange)
+                        {
+                            addedColumns.add(((AddColumnChange)change).getNewColumn().getName());
+                        }
+                        else if (change instanceof AddPrimaryKeyChange)
+                        {
+                            pkColNames = ((AddPrimaryKeyChange)change).getPrimaryKeyColumns();
+                        }
+                        else if (change instanceof PrimaryKeyChange)
+                        {
+                            pkColNames = ((PrimaryKeyChange)change).getNewPrimaryKeyColumns();
+                        }
+                    }
+                    if (pkColNames != null)
+                    {
+                        for (int colIdx = 0; colIdx < pkColNames.length; colIdx++)
+                        {
+                            if (addedColumns.contains(pkColNames[colIdx]))
+                            {
+                                return false;
+                            }
+                        }
+                    }
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            protected boolean isSupported(Table intermediateTable, TableChange change)
+            {
+                // Firebird cannot add columns to the primary key or drop columns from it but
+                // since we add/drop the primary key with separate changes anyways, this will
+                // no problem here
+                if ((change instanceof RemoveColumnChange) ||
+                    (change instanceof AddColumnChange))
+                {
+                    return true;
+                }
+                else
+                {
+                    return super.isSupported(intermediateTable, change);
+                }
+            }
+        };
+    }
+
+    /**
+     * Processes the addition of a column to a table.
+     * 
+     * @param currentModel The current database schema
+     * @param params       The parameters used in the creation of new tables. Note that for existing
+     *                     tables, the parameters won't be applied
+     * @param change       The change object
+     */
+    public void processChange(Database           currentModel,
+                              CreationParameters params,
+                              AddColumnChange    change) throws IOException
+    {
+        Table  changedTable = findChangedTable(currentModel, change);
+        Column prevColumn   = null;
+
+        if (change.getPreviousColumn() != null)
+        {
+            prevColumn = changedTable.findColumn(change.getPreviousColumn(), isDelimitedIdentifierModeOn());
+        }
+        ((FirebirdBuilder)getSqlBuilder()).insertColumn(currentModel,
+                                                        changedTable,
+                                                        change.getNewColumn(),
+                                                        prevColumn);
+        change.apply(currentModel, isDelimitedIdentifierModeOn());
+    }
+
+    /**
+     * Processes the removal of a column from a table.
+     * 
+     * @param currentModel The current database schema
+     * @param params       The parameters used in the creation of new tables. Note that for existing
+     *                     tables, the parameters won't be applied
+     * @param change       The change object
+     */
+    public void processChange(Database           currentModel,
+                              CreationParameters params,
+                              RemoveColumnChange change) throws IOException
+    {
+        Table  changedTable  = findChangedTable(currentModel, change);
+        Column droppedColumn = changedTable.findColumn(change.getChangedColumn(), isDelimitedIdentifierModeOn());
+
+        ((FirebirdBuilder)getSqlBuilder()).dropColumn(changedTable, droppedColumn);
+        change.apply(currentModel, isDelimitedIdentifierModeOn());
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java Mon Dec 10 00:20:47 2007
@@ -20,17 +20,9 @@
  */
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
 
 import org.apache.ddlutils.Platform;
-import org.apache.ddlutils.alteration.AddColumnChange;
-import org.apache.ddlutils.alteration.RemoveColumnChange;
-import org.apache.ddlutils.alteration.TableChange;
-import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Table;
 import org.apache.ddlutils.platform.SqlBuilder;
 
@@ -72,108 +64,41 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    protected void processTableStructureChanges(Database currentModel,
-                                                Database desiredModel,
-                                                Table    sourceTable,
-                                                Table    targetTable,
-                                                Map      parameters,
-                                                List     changes) throws IOException
-    {
-        // HsqlDb can only drop columns that are not part of a primary key
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if ((change instanceof RemoveColumnChange) && 
-                ((RemoveColumnChange)change).getChangedColumn().isPrimaryKey())
-            {
-                return;
-            }
-        }
-
-        // in order to utilize the ALTER TABLE ADD COLUMN BEFORE statement
-        // we have to apply the add column changes in the correct order
-        // thus we first gather all add column changes and then execute them
-        // Since we get them in target table column order, we can simply
-        // iterate backwards
-        ArrayList addColumnChanges = new ArrayList();
-
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if (change instanceof AddColumnChange)
-            {
-                addColumnChanges.add(change);
-                changeIt.remove();
-            }
-        }
-        for (ListIterator changeIt = addColumnChanges.listIterator(addColumnChanges.size()); changeIt.hasPrevious();)
-        {
-            AddColumnChange addColumnChange = (AddColumnChange)changeIt.previous();
-
-            processChange(currentModel, desiredModel, addColumnChange);
-            changeIt.remove();
-        }
-
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if (change instanceof RemoveColumnChange) 
-            {
-                RemoveColumnChange removeColumnChange = (RemoveColumnChange)change;
-
-                processChange(currentModel, desiredModel, removeColumnChange);
-                changeIt.remove();
-            }
-        }
-    }
-
-    /**
-     * Processes the addition of a column to a table.
+     * Writes the SQL to add/insert a column.
      * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
+     * @param table      The table
+     * @param newColumn  The new column
+     * @param nextColumn The column before which the new column shall be added; <code>null</code>
+     *                   if the new column is to be added instead of inserted
      */
-    protected void processChange(Database        currentModel,
-                                 Database        desiredModel,
-                                 AddColumnChange change) throws IOException
+    public void insertColumn(Table table, Column newColumn, Column nextColumn) throws IOException
     {
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(change.getChangedTable()));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("ADD COLUMN ");
-        writeColumn(change.getChangedTable(), change.getNewColumn());
-        if (change.getNextColumn() != null)
+        writeColumn(table, newColumn);
+        if (nextColumn != null)
         {
             print(" BEFORE ");
-            printIdentifier(getColumnName(change.getNextColumn()));
+            printIdentifier(getColumnName(nextColumn));
         }
         printEndOfStatement();
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
     }
 
     /**
-     * Processes the removal of a column from a table.
+     * Writes the SQL to drop a column.
      * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
+     * @param table  The table
+     * @param column The column to drop
      */
-    protected void processChange(Database           currentModel,
-                                 Database           desiredModel,
-                                 RemoveColumnChange change) throws IOException
+    public void dropColumn(Table table, Column column) throws IOException
     {
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(change.getChangedTable()));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("DROP COLUMN ");
-        printIdentifier(getColumnName(change.getChangedColumn()));
+        printIdentifier(getColumnName(column));
         printEndOfStatement();
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbPlatform.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbPlatform.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbPlatform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbPlatform.java Mon Dec 10 00:20:47 2007
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import java.io.IOException;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.Statement;
@@ -26,6 +27,16 @@
 
 import org.apache.ddlutils.DdlUtilsException;
 import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.alteration.AddColumnChange;
+import org.apache.ddlutils.alteration.AddPrimaryKeyChange;
+import org.apache.ddlutils.alteration.RemoveColumnChange;
+import org.apache.ddlutils.alteration.TableChange;
+import org.apache.ddlutils.alteration.TableDefinitionChangesPredicate;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.platform.CreationParameters;
+import org.apache.ddlutils.platform.DefaultTableDefinitionChangesPredicate;
 import org.apache.ddlutils.platform.PlatformImplBase;
 
 /**
@@ -52,6 +63,7 @@
         info.setNonPKIdentityColumnsSupported(false);
         info.setIdentityOverrideAllowed(false);
         info.setSystemForeignKeyIndicesAlwaysNonUnique(true);
+        info.setPrimaryKeyColumnAutomaticallyRequired(true);
 
         info.addNativeTypeMapping(Types.ARRAY,       "LONGVARBINARY", Types.LONGVARBINARY);
         info.addNativeTypeMapping(Types.BLOB,        "LONGVARBINARY", Types.LONGVARBINARY);
@@ -105,5 +117,86 @@
         {
             closeStatement(stmt);    
         }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected TableDefinitionChangesPredicate getTableDefinitionChangesPredicate()
+    {
+        return new DefaultTableDefinitionChangesPredicate()
+        {
+            protected boolean isSupported(Table intermediateTable, TableChange change)
+            {
+                if (change instanceof RemoveColumnChange)
+                {
+                    Column column = intermediateTable.findColumn(((RemoveColumnChange)change).getChangedColumn(),
+                                                                 isDelimitedIdentifierModeOn());
+
+                    // HsqlDb can only drop columns that are not part of a primary key
+                    return !column.isPrimaryKey();
+                }
+                else if (change instanceof AddColumnChange)
+                {
+                    AddColumnChange addColumnChange = (AddColumnChange)change; 
+
+                    // adding IDENTITY columns is not supported without a table rebuild because they have to
+                    // be PK columns, but we add them to the PK later
+                    return addColumnChange.isAtEnd() &&
+                           (!addColumnChange.getNewColumn().isRequired() ||
+                            (addColumnChange.getNewColumn().getDefaultValue() != null));
+                }
+                else if (change instanceof AddPrimaryKeyChange)
+                {
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+        };
+    }
+
+    /**
+     * Processes the addition of a column to a table.
+     * 
+     * @param currentModel The current database schema
+     * @param params       The parameters used in the creation of new tables. Note that for existing
+     *                     tables, the parameters won't be applied
+     * @param change       The change object
+     */
+    public void processChange(Database           currentModel,
+                              CreationParameters params,
+                              AddColumnChange    change) throws IOException
+    {
+        Table  changedTable = findChangedTable(currentModel, change);
+        Column nextColumn   = null;
+
+        if (change.getNextColumn() != null)
+        {
+            nextColumn = changedTable.findColumn(change.getNextColumn(), isDelimitedIdentifierModeOn());
+        }
+        ((HsqlDbBuilder)getSqlBuilder()).insertColumn(changedTable, change.getNewColumn(), nextColumn);
+        change.apply(currentModel, isDelimitedIdentifierModeOn());
+    }
+
+    /**
+     * Processes the removal of a column from a table.
+     * 
+     * @param currentModel The current database schema
+     * @param params       The parameters used in the creation of new tables. Note that for existing
+     *                     tables, the parameters won't be applied
+     * @param change       The change object
+     */
+    public void processChange(Database           currentModel,
+                              CreationParameters params,
+                              RemoveColumnChange change) throws IOException
+    {
+        Table  changedTable  = findChangedTable(currentModel, change);
+        Column removedColumn = changedTable.findColumn(change.getChangedColumn(), isDelimitedIdentifierModeOn());
+
+        ((HsqlDbBuilder)getSqlBuilder()).dropColumn(changedTable, removedColumn);
+        change.apply(currentModel, isDelimitedIdentifierModeOn());
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbaseBuilder.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbaseBuilder.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbaseBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbaseBuilder.java Mon Dec 10 00:20:47 2007
@@ -21,15 +21,9 @@
 
 import java.io.IOException;
 import java.sql.Types;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.ddlutils.Platform;
-import org.apache.ddlutils.alteration.AddColumnChange;
-import org.apache.ddlutils.alteration.AddPrimaryKeyChange;
-import org.apache.ddlutils.alteration.RemoveColumnChange;
-import org.apache.ddlutils.alteration.TableChange;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.Index;
@@ -105,7 +99,7 @@
     /**
      * {@inheritDoc}
      */
-    public void writeExternalIndexDropStmt(Table table, Index index) throws IOException
+    public void dropIndex(Table table, Index index) throws IOException
     {
         // Index names in Interbase are unique to a schema and hence we do not
         // need the ON <tablename> clause
@@ -219,133 +213,59 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    protected void processTableStructureChanges(Database currentModel, Database desiredModel, Table sourceTable, Table targetTable, Map parameters, List changes) throws IOException
-    {
-        // TODO: Dropping of primary keys is currently not supported because we cannot
-        //       determine the pk constraint names and drop them in one go
-        //       (We could used a stored procedure if Interbase would allow them to use DDL)
-        //       This will be easier once named primary keys are supported
-        boolean pkColumnAdded = false;
-
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if (change instanceof AddColumnChange)
-            {
-                AddColumnChange addColumnChange = (AddColumnChange)change;
-
-                // TODO: we cannot add columns to the primary key this way
-                //       because we would have to drop the pk first and then
-                //       add a new one afterwards which is not supported yet
-                if (addColumnChange.getNewColumn().isPrimaryKey())
-                {
-                    pkColumnAdded = true;   
-                }
-                else
-                {
-                    processChange(currentModel, desiredModel, addColumnChange);
-                    changeIt.remove();
-                }
-            }
-            else if (change instanceof RemoveColumnChange)
-            {
-                RemoveColumnChange removeColumnChange = (RemoveColumnChange)change;
-
-                // TODO: we cannot drop primary key columns this way
-                //       because we would have to drop the pk first and then
-                //       add a new one afterwards which is not supported yet
-                if (!removeColumnChange.getChangedColumn().isPrimaryKey())
-                {
-                    processChange(currentModel, desiredModel, removeColumnChange);
-                    changeIt.remove();
-                }
-            }
-        }
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            // we can only add a primary key if all columns are present in the table
-            // i.e. none was added during this alteration
-            if ((change instanceof AddPrimaryKeyChange) && !pkColumnAdded)
-            {
-                processChange(currentModel, desiredModel, (AddPrimaryKeyChange)change);
-                changeIt.remove();
-            }
-        }
-    }
-
-    /**
-     * Processes the addition of a column to a table.
+     * Writes the SQL to add/insert a column.
      * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
-     */
-    protected void processChange(Database        currentModel,
-                                 Database        desiredModel,
-                                 AddColumnChange change) throws IOException
+     * @param model      The database model
+     * @param table      The table
+     * @param newColumn  The new column
+     * @param prevColumn The column after which the new column shall be added; <code>null</code>
+     *                   if the new column is to be inserted at the beginning
+     */
+    public void insertColumn(Database model, Table table, Column newColumn, Column prevColumn) throws IOException
     {
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(change.getChangedTable()));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("ADD ");
-        writeColumn(change.getChangedTable(), change.getNewColumn());
+        writeColumn(table, newColumn);
         printEndOfStatement();
 
-        Table curTable = currentModel.findTable(change.getChangedTable().getName(), getPlatform().isDelimitedIdentifierModeOn());
-
-        if (!change.isAtEnd())
+        if (prevColumn != null)
         {
-            Column prevColumn = change.getPreviousColumn();
-
-            if (prevColumn != null)
-            {
-                // we need the corresponding column object from the current table
-                prevColumn = curTable.findColumn(prevColumn.getName(), getPlatform().isDelimitedIdentifierModeOn());
-            }
             // Even though Interbase can only add columns, we can move them later on
             print("ALTER TABLE ");
-            printlnIdentifier(getTableName(change.getChangedTable()));
+            printlnIdentifier(getTableName(table));
             printIndent();
             print("ALTER ");
-            printIdentifier(getColumnName(change.getNewColumn()));
+            printIdentifier(getColumnName(newColumn));
             print(" POSITION ");
             // column positions start at 1 in Interbase
-            print(prevColumn == null ? "1" : String.valueOf(curTable.getColumnIndex(prevColumn) + 2));
+            print(String.valueOf(table.getColumnIndex(prevColumn) + 2));
             printEndOfStatement();
         }
-        if (change.getNewColumn().isAutoIncrement())
+        if (newColumn.isAutoIncrement())
         {
-            writeAutoIncrementCreateStmts(currentModel, curTable, change.getNewColumn());
+            writeAutoIncrementCreateStmts(model, table, newColumn);
         }
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
     }
 
     /**
-     * Processes the removal of a column from a table.
+     * Writes the SQL to drop a column.
      * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
-     */
-    protected void processChange(Database           currentModel,
-                                 Database           desiredModel,
-                                 RemoveColumnChange change) throws IOException
+     * @param table  The table
+     * @param column The column to drop
+     */
+    public void dropColumn(Table table, Column column) throws IOException
     {
-        if (change.getChangedColumn().isAutoIncrement())
+        if (column.isAutoIncrement())
         {
-            writeAutoIncrementDropStmts(change.getChangedTable(), change.getChangedColumn());
+            writeAutoIncrementDropStmts(table, column);
         }
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(change.getChangedTable()));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("DROP ");
-        printIdentifier(getColumnName(change.getChangedColumn()));
+        printIdentifier(getColumnName(column));
         printEndOfStatement();
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbasePlatform.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbasePlatform.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbasePlatform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/interbase/InterbasePlatform.java Mon Dec 10 00:20:47 2007
@@ -27,9 +27,24 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Types;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
 
 import org.apache.ddlutils.DdlUtilsException;
 import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.alteration.AddColumnChange;
+import org.apache.ddlutils.alteration.AddPrimaryKeyChange;
+import org.apache.ddlutils.alteration.ModelComparator;
+import org.apache.ddlutils.alteration.PrimaryKeyChange;
+import org.apache.ddlutils.alteration.RemoveColumnChange;
+import org.apache.ddlutils.alteration.TableChange;
+import org.apache.ddlutils.alteration.TableDefinitionChangesPredicate;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.platform.CreationParameters;
+import org.apache.ddlutils.platform.DefaultTableDefinitionChangesPredicate;
 import org.apache.ddlutils.platform.PlatformImplBase;
 
 /**
@@ -172,4 +187,130 @@
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    protected ModelComparator getModelComparator()
+    {
+        ModelComparator comparator = super.getModelComparator();
+
+        comparator.setCanDropPrimaryKeyColumns(false);
+        comparator.setGeneratePrimaryKeyChanges(false);
+        return comparator;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected TableDefinitionChangesPredicate getTableDefinitionChangesPredicate()
+    {
+        return new DefaultTableDefinitionChangesPredicate()
+        {
+            public boolean areSupported(Table intermediateTable, List changes)
+            {
+                // Firebird does support adding a primary key, but only if none of the primary
+                // key columns have been added within the same session
+                if (super.areSupported(intermediateTable, changes))
+                {
+                    HashSet  addedColumns = new HashSet();
+                    String[] pkColNames   = null;
+
+                    for (Iterator it = changes.iterator(); it.hasNext();)
+                    {
+                        TableChange change = (TableChange)it.next();
+
+                        if (change instanceof AddColumnChange)
+                        {
+                            addedColumns.add(((AddColumnChange)change).getNewColumn().getName());
+                        }
+                        else if (change instanceof AddPrimaryKeyChange)
+                        {
+                            pkColNames = ((AddPrimaryKeyChange)change).getPrimaryKeyColumns();
+                        }
+                        else if (change instanceof PrimaryKeyChange)
+                        {
+                            pkColNames = ((PrimaryKeyChange)change).getNewPrimaryKeyColumns();
+                        }
+                    }
+                    if (pkColNames != null)
+                    {
+                        for (int colIdx = 0; colIdx < pkColNames.length; colIdx++)
+                        {
+                            if (addedColumns.contains(pkColNames[colIdx]))
+                            {
+                                return false;
+                            }
+                        }
+                    }
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            protected boolean isSupported(Table intermediateTable, TableChange change)
+            {
+                // Firebird cannot add columns to the primary key or drop columns from it but
+                // since we add/drop the primary key with separate changes anyways, this will
+                // no problem here
+                if ((change instanceof RemoveColumnChange) ||
+                    (change instanceof AddColumnChange))
+                {
+                    return true;
+                }
+                else
+                {
+                    return super.isSupported(intermediateTable, change);
+                }
+            }
+        };
+    }
+
+
+    /**
+     * Processes the addition of a column to a table.
+     * 
+     * @param currentModel The current database schema
+     * @param params       The parameters used in the creation of new tables. Note that for existing
+     *                     tables, the parameters won't be applied
+     * @param change       The change object
+     */
+    public void processChange(Database           currentModel,
+                              CreationParameters params,
+                              AddColumnChange    change) throws IOException
+    {
+        Table  changedTable = findChangedTable(currentModel, change);
+        Column prevColumn   = null;
+
+        if (change.getPreviousColumn() != null)
+        {
+            prevColumn = changedTable.findColumn(change.getPreviousColumn(), isDelimitedIdentifierModeOn());
+        }
+        ((InterbaseBuilder)getSqlBuilder()).insertColumn(currentModel,
+                                                         changedTable,
+                                                         change.getNewColumn(),
+                                                         prevColumn);
+        change.apply(currentModel, isDelimitedIdentifierModeOn());
+    }
+
+    /**
+     * Processes the removal of a column from a table.
+     * 
+     * @param currentModel The current database schema
+     * @param params       The parameters used in the creation of new tables. Note that for existing
+     *                     tables, the parameters won't be applied
+     * @param change       The change object
+     */
+    public void processChange(Database           currentModel,
+                              CreationParameters params,
+                              RemoveColumnChange change) throws IOException
+    {
+        Table  changedTable  = findChangedTable(currentModel, change);
+        Column droppedColumn = changedTable.findColumn(change.getChangedColumn(), isDelimitedIdentifierModeOn());
+
+        ((InterbaseBuilder)getSqlBuilder()).dropColumn(changedTable, droppedColumn);
+        change.apply(currentModel, isDelimitedIdentifierModeOn());
+    }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/maxdb/MaxDbBuilder.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/maxdb/MaxDbBuilder.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/maxdb/MaxDbBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/maxdb/MaxDbBuilder.java Mon Dec 10 00:20:47 2007
@@ -48,7 +48,7 @@
     /**
      * {@inheritDoc}
      */
-    protected void writeExternalPrimaryKeysCreateStmt(Table table, Column[] primaryKeyColumns) throws IOException
+    public void createPrimaryKey(Table table, Column[] primaryKeyColumns) throws IOException
     {
         if ((primaryKeyColumns.length > 0) && shouldGeneratePrimaryKeys(primaryKeyColumns))
         {
@@ -66,24 +66,24 @@
     /**
      * {@inheritDoc}
      */
-    protected void writeExternalForeignKeyCreateStmt(Database database, Table table, ForeignKey key) throws IOException
+    public void createForeignKey(Database database, Table table, ForeignKey foreignKey) throws IOException
     {
-        if (key.getForeignTableName() == null)
+        if (foreignKey.getForeignTableName() == null)
         {
-            _log.warn("Foreign key table is null for key " + key);
+            _log.warn("Foreign key table is null for key " + foreignKey);
         }
         else
         {
             writeTableAlterStmt(table);
 
             print("ADD CONSTRAINT ");
-            printIdentifier(getForeignKeyName(table, key));
+            printIdentifier(getForeignKeyName(table, foreignKey));
             print(" FOREIGN KEY (");
-            writeLocalReferences(key);
+            writeLocalReferences(foreignKey);
             print(") REFERENCES ");
-            printIdentifier(getTableName(database.findTable(key.getForeignTableName())));
+            printIdentifier(getTableName(database.findTable(foreignKey.getForeignTableName())));
             print(" (");
-            writeForeignReferences(key);
+            writeForeignReferences(foreignKey);
             print(")");
             printEndOfStatement();
         }
@@ -92,7 +92,7 @@
     /**
      * {@inheritDoc}
      */
-    protected void writeExternalForeignKeyDropStmt(Table table, ForeignKey foreignKey) throws IOException
+    public void dropForeignKey(Table table, ForeignKey foreignKey) throws IOException
     {
         writeTableAlterStmt(table);
         print("DROP CONSTRAINT ");

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiBuilder.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiBuilder.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiBuilder.java Mon Dec 10 00:20:47 2007
@@ -20,15 +20,9 @@
  */
 
 import java.io.IOException;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.ddlutils.Platform;
-import org.apache.ddlutils.alteration.AddColumnChange;
-import org.apache.ddlutils.alteration.ColumnAutoIncrementChange;
-import org.apache.ddlutils.alteration.RemoveColumnChange;
-import org.apache.ddlutils.alteration.TableChange;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.Table;
@@ -172,77 +166,15 @@
     }
 
     /**
-     * {@inheritDoc}
+     * Writes the SQL to recreate a table.
+     * 
+     * @param model      The database model
+     * @param table      The table to recreate
+     * @param parameters The table creation parameters
      */
-    protected void processTableStructureChanges(Database currentModel,
-                                                Database desiredModel,
-                                                Table    sourceTable,
-                                                Table    targetTable,
-                                                Map      parameters,
-                                                List     changes) throws IOException
-    {
-        // McKoi has this nice ALTER CREATE TABLE statement which saves us a lot of work
-        // We only have to handle auto-increment changes manually
-        for (Iterator it = changes.iterator(); it.hasNext();)
-        {
-            TableChange change = (TableChange)it.next();
-
-            if (change instanceof ColumnAutoIncrementChange)
-            {
-                Column column = ((ColumnAutoIncrementChange)change).getChangedColumn();
-
-                // we have to defer removal of the sequences until they are no longer used
-                if (!column.isAutoIncrement())
-                {
-                    ColumnAutoIncrementChange autoIncrChange = (ColumnAutoIncrementChange)change;
-
-                    createAutoIncrementSequence(autoIncrChange.getChangedTable(),
-                                                autoIncrChange.getChangedColumn());
-                }
-            }
-            else if (change instanceof AddColumnChange)
-            {
-                AddColumnChange addColumnChange = (AddColumnChange)change;
-
-                if (addColumnChange.getNewColumn().isAutoIncrement())
-                {
-                    createAutoIncrementSequence(addColumnChange.getChangedTable(),
-                                                addColumnChange.getNewColumn());
-                }
-            }
-        }
-
+    protected void writeRecreateTableStmt(Database model, Table table, Map parameters) throws IOException
+    {
         print("ALTER ");
-        super.createTable(desiredModel, targetTable, parameters);
-
-        for (Iterator it = changes.iterator(); it.hasNext();)
-        {
-            TableChange change = (TableChange)it.next();
-    
-            if (change instanceof ColumnAutoIncrementChange)
-            {
-                Column column = ((ColumnAutoIncrementChange)change).getChangedColumn();
-    
-                if (column.isAutoIncrement())
-                {
-                    ColumnAutoIncrementChange autoIncrChange = (ColumnAutoIncrementChange)change;
-        
-                    dropAutoIncrementSequence(autoIncrChange.getChangedTable(),
-                                              autoIncrChange.getChangedColumn());
-                }
-            }
-            else if (change instanceof RemoveColumnChange)
-            {
-                RemoveColumnChange removeColumnChange = (RemoveColumnChange)change;
-
-                if (removeColumnChange.getChangedColumn().isAutoIncrement())
-                {
-                    dropAutoIncrementSequence(removeColumnChange.getChangedTable(),
-                                              removeColumnChange.getChangedColumn());
-                }
-            }
-        }
-        changes.clear();
+        super.createTable(model, table, parameters);
     }
 }
-

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiPlatform.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiPlatform.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiPlatform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mckoi/MckoiPlatform.java Mon Dec 10 00:20:47 2007
@@ -19,15 +19,28 @@
  * under the License.
  */
 
+import java.io.IOException;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
 import java.sql.Types;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.ddlutils.DatabaseOperationException;
 import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.alteration.AddColumnChange;
+import org.apache.ddlutils.alteration.ColumnDefinitionChange;
+import org.apache.ddlutils.alteration.RecreateTableChange;
+import org.apache.ddlutils.alteration.RemoveColumnChange;
+import org.apache.ddlutils.alteration.TableChange;
+import org.apache.ddlutils.alteration.TableDefinitionChangesPredicate;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.platform.CreationParameters;
+import org.apache.ddlutils.platform.DefaultTableDefinitionChangesPredicate;
 import org.apache.ddlutils.platform.PlatformImplBase;
 
 /**
@@ -147,7 +160,93 @@
         }
         else
         {
-            throw new UnsupportedOperationException("Unable to create a Derby database via the driver "+jdbcDriverClassName);
+            throw new UnsupportedOperationException("Unable to create a McKoi database via the driver "+jdbcDriverClassName);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected TableDefinitionChangesPredicate getTableDefinitionChangesPredicate()
+    {
+        return new DefaultTableDefinitionChangesPredicate()
+        {
+            public boolean areSupported(Table intermediateTable, List changes)
+            {
+                // McKoi has this nice ALTER CREATE TABLE statement which saves us a lot of work
+                // Thus, we reject all table level changes and instead redefine the handling of the
+                // RecreateTableChange
+                return false;
+            }
+        };
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void processChange(Database currentModel, CreationParameters params, RecreateTableChange change) throws IOException
+    {
+        // McKoi has this nice ALTER CREATE TABLE statement which saves us a lot of work
+        // We only have to handle auto-increment changes manually
+        MckoiBuilder sqlBuilder   = (MckoiBuilder)getSqlBuilder();
+        Table        changedTable = findChangedTable(currentModel, change);
+
+        for (Iterator it = change.getOriginalChanges().iterator(); it.hasNext();)
+        {
+            TableChange tableChange = (TableChange)it.next();
+
+            if (tableChange instanceof ColumnDefinitionChange)
+            {
+                ColumnDefinitionChange colChange  = (ColumnDefinitionChange)tableChange;
+                Column                 origColumn = changedTable.findColumn(colChange.getChangedColumn(), isDelimitedIdentifierModeOn());
+                Column                 newColumn  = colChange.getNewColumn();
+
+                if (!origColumn.isAutoIncrement() && newColumn.isAutoIncrement())
+                {
+                    sqlBuilder.createAutoIncrementSequence(changedTable, origColumn);
+                }
+            }
+            else if (tableChange instanceof AddColumnChange)
+            {
+                AddColumnChange addColumnChange = (AddColumnChange)tableChange;
+
+                if (addColumnChange.getNewColumn().isAutoIncrement())
+                {
+                    sqlBuilder.createAutoIncrementSequence(changedTable, addColumnChange.getNewColumn());
+                }
+            }
+        }
+
+        Map parameters = (params == null ? null : params.getParametersFor(changedTable));
+        
+        sqlBuilder.writeRecreateTableStmt(currentModel, change.getTargetTable(), parameters);
+
+        // we have to defer removal of the sequences until they are no longer used
+        for (Iterator it = change.getOriginalChanges().iterator(); it.hasNext();)
+        {
+            TableChange tableChange = (TableChange)it.next();
+    
+            if (tableChange instanceof ColumnDefinitionChange)
+            {
+                ColumnDefinitionChange colChange  = (ColumnDefinitionChange)tableChange;
+                Column                 origColumn = changedTable.findColumn(colChange.getChangedColumn(), isDelimitedIdentifierModeOn());
+                Column                 newColumn  = colChange.getNewColumn();
+
+                if (origColumn.isAutoIncrement() && !newColumn.isAutoIncrement())
+                {
+                    sqlBuilder.dropAutoIncrementSequence(changedTable, origColumn);
+                }
+            }
+            else if (tableChange instanceof RemoveColumnChange)
+            {
+                RemoveColumnChange removeColumnChange = (RemoveColumnChange)tableChange;
+                Column             removedColumn      = changedTable.findColumn(removeColumnChange.getChangedColumn(), isDelimitedIdentifierModeOn());
+
+                if (removedColumn.isAutoIncrement())
+                {
+                    sqlBuilder.dropAutoIncrementSequence(changedTable, removedColumn);
+                }
+            }
         }
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlBuilder.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlBuilder.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlBuilder.java Mon Dec 10 00:20:47 2007
@@ -23,33 +23,15 @@
 import java.sql.Types;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.ddlutils.Platform;
-import org.apache.ddlutils.alteration.AddColumnChange;
-import org.apache.ddlutils.alteration.AddForeignKeyChange;
-import org.apache.ddlutils.alteration.AddIndexChange;
-import org.apache.ddlutils.alteration.AddPrimaryKeyChange;
-import org.apache.ddlutils.alteration.ColumnAutoIncrementChange;
-import org.apache.ddlutils.alteration.ColumnChange;
-import org.apache.ddlutils.alteration.ColumnDataTypeChange;
-import org.apache.ddlutils.alteration.ColumnSizeChange;
-import org.apache.ddlutils.alteration.PrimaryKeyChange;
-import org.apache.ddlutils.alteration.RemoveColumnChange;
-import org.apache.ddlutils.alteration.RemoveForeignKeyChange;
-import org.apache.ddlutils.alteration.RemoveIndexChange;
-import org.apache.ddlutils.alteration.RemovePrimaryKeyChange;
-import org.apache.ddlutils.alteration.TableChange;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.ForeignKey;
 import org.apache.ddlutils.model.Index;
 import org.apache.ddlutils.model.Table;
-import org.apache.ddlutils.platform.CreationParameters;
 import org.apache.ddlutils.platform.SqlBuilder;
 import org.apache.ddlutils.util.Jdbc3Utils;
 
@@ -81,7 +63,7 @@
      */
     public void createTable(Database database, Table table, Map parameters) throws IOException
     {
-        writeQuotationOnStatement();
+        turnOnQuotation();
         super.createTable(database, table, parameters);
     }
 
@@ -94,7 +76,7 @@
         String tableNameVar      = "tn" + createUniqueIdentifier();
         String constraintNameVar = "cn" + createUniqueIdentifier();
 
-        writeQuotationOnStatement();
+        turnOnQuotation();
         print("IF EXISTS (SELECT 1 FROM sysobjects WHERE type = 'U' AND name = ");
         printAlwaysSingleQuotedIdentifier(tableName);
         println(")");
@@ -123,10 +105,10 @@
     /**
      * {@inheritDoc}
      */
-    public void dropExternalForeignKeys(Table table) throws IOException
+    public void dropForeignKeys(Table table) throws IOException
     {
-        writeQuotationOnStatement();
-        super.dropExternalForeignKeys(table);
+        turnOnQuotation();
+        super.dropForeignKeys(table);
     }
 
     /**
@@ -227,7 +209,7 @@
     /**
      * {@inheritDoc}
      */
-    public void writeExternalIndexDropStmt(Table table, Index index) throws IOException
+    public void dropIndex(Table table, Index index) throws IOException
     {
         print("DROP INDEX ");
         printIdentifier(getTableName(table));
@@ -239,7 +221,7 @@
     /**
      * {@inheritDoc}
      */
-    protected void writeExternalForeignKeyDropStmt(Table table, ForeignKey foreignKey) throws IOException
+    public void dropForeignKey(Table table, ForeignKey foreignKey) throws IOException
     {
         String constraintName = getForeignKeyName(table, foreignKey);
 
@@ -272,9 +254,9 @@
     }
 
     /**
-     * Writes the statement that turns on the ability to write delimited identifiers.
+     * If quotation mode is on, then this writes the statement that turns on the ability to write delimited identifiers.
      */
-    private void writeQuotationOnStatement() throws IOException
+    protected void turnOnQuotation() throws IOException
     {
         print(getQuotationOnStatement());
     }
@@ -365,7 +347,7 @@
     /**
      * {@inheritDoc}
      */
-    protected void writeCopyDataStatement(Table sourceTable, Table targetTable) throws IOException
+    protected void copyData(Table sourceTable, Table targetTable) throws IOException
     {
         // Sql Server per default does not allow us to insert values explicitly into
         // identity columns. However, we can change this behavior
@@ -378,7 +360,7 @@
             print(" ON");
             printEndOfStatement();
         }
-        super.writeCopyDataStatement(sourceTable, targetTable);
+        super.copyData(sourceTable, targetTable);
         // We have to turn it off ASAP because it can be on only for one table per session
         if (hasIdentityColumns)
         {
@@ -392,363 +374,141 @@
     /**
      * {@inheritDoc}
      */
-    protected void processChanges(Database currentModel, Database desiredModel, List changes, CreationParameters params) throws IOException
-    {
-        if (!changes.isEmpty())
-        {
-            writeQuotationOnStatement();
-        }
-        // For column data type and size changes, we need to drop and then re-create indexes
-        // and foreign keys using the column, as well as any primary keys containg
-        // these columns
-        // However, if the index/foreign key/primary key is already slated for removal or
-        // change, then we don't want to generate change duplication
-        HashSet removedIndexes     = new HashSet();
-        HashSet removedForeignKeys = new HashSet();
-        HashSet removedPKs         = new HashSet();
-
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            Object change = changeIt.next();
-
-            if (change instanceof RemoveIndexChange)
-            {
-                removedIndexes.add(((RemoveIndexChange)change).getChangedIndex());
-            }
-            else if (change instanceof RemoveForeignKeyChange)
-            {
-                removedForeignKeys.add(((RemoveForeignKeyChange)change).getChangedForeignKey());
-            }
-            else if (change instanceof RemovePrimaryKeyChange)
-            {
-                removedPKs.add(((RemovePrimaryKeyChange)change).getChangedTable());
-            }
-        }
-
-        ArrayList additionalChanges = new ArrayList();
-
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            Object change = changeIt.next();
-
-            if ((change instanceof ColumnDataTypeChange) ||
-                (change instanceof ColumnSizeChange))
-            {
-                Column column = ((ColumnChange)change).getChangedColumn();
-                Table  table  = ((ColumnChange)change).getChangedTable();
-
-                if (column.isPrimaryKey() && !removedPKs.contains(table))
-                {
-                    Column[] pk = table.getPrimaryKeyColumns();
-
-                    additionalChanges.add(new RemovePrimaryKeyChange(table, pk));
-                    additionalChanges.add(new AddPrimaryKeyChange(table, pk));
-                    removedPKs.add(table);
-                }
-                for (int idx = 0; idx < table.getIndexCount(); idx++)
-                {
-                    Index index = table.getIndex(idx);
-
-                    if (index.hasColumn(column) && !removedIndexes.contains(index))
-                    {
-                        additionalChanges.add(new RemoveIndexChange(table, index));
-                        additionalChanges.add(new AddIndexChange(table, index));
-                        removedIndexes.add(index);
-                    }
-                }
-                for (int tableIdx = 0; tableIdx < currentModel.getTableCount(); tableIdx++)
-                {
-                    Table curTable = currentModel.getTable(tableIdx);
-
-                    for (int fkIdx = 0; fkIdx < curTable.getForeignKeyCount(); fkIdx++)
-                    {
-                        ForeignKey curFk = curTable.getForeignKey(fkIdx);
-
-                        if ((curFk.hasLocalColumn(column) || curFk.hasForeignColumn(column)) &&
-                            !removedForeignKeys.contains(curFk))
-                        {
-                            additionalChanges.add(new RemoveForeignKeyChange(curTable, curFk));
-                            additionalChanges.add(new AddForeignKeyChange(curTable, curFk));
-                            removedForeignKeys.add(curFk);
-                        }
-                    }
-                }
-            }
-        }
-        changes.addAll(additionalChanges);
-        super.processChanges(currentModel, desiredModel, changes, params);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected void processTableStructureChanges(Database currentModel,
-                                                Database desiredModel,
-                                                Table    sourceTable,
-                                                Table    targetTable,
-                                                Map      parameters,
-                                                List     changes) throws IOException
-    {
-        // First we drop primary keys as necessary
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if (change instanceof RemovePrimaryKeyChange)
-            {
-                processChange(currentModel, desiredModel, (RemovePrimaryKeyChange)change);
-                changeIt.remove();
-            }
-            else if (change instanceof PrimaryKeyChange)
-            {
-                PrimaryKeyChange       pkChange       = (PrimaryKeyChange)change;
-                RemovePrimaryKeyChange removePkChange = new RemovePrimaryKeyChange(pkChange.getChangedTable(),
-                                                                                   pkChange.getOldPrimaryKeyColumns());
-
-                processChange(currentModel, desiredModel, removePkChange);
-            }
-        }
-
-        ArrayList columnChanges = new ArrayList();
-
-        // Next we add/remove columns
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if (change instanceof AddColumnChange)
-            {
-                AddColumnChange addColumnChange = (AddColumnChange)change;
-
-                // Sql Server can only add not insert columns
-                if (addColumnChange.isAtEnd())
-                {
-                    processChange(currentModel, desiredModel, addColumnChange);
-                    changeIt.remove();
-                }
-            }
-            else if (change instanceof RemoveColumnChange)
-            {
-                processChange(currentModel, desiredModel, (RemoveColumnChange)change);
-                changeIt.remove();
-            }
-            else if (change instanceof ColumnAutoIncrementChange)
-            {
-                // Sql Server has no way of adding or removing an IDENTITY constraint
-                // Thus we have to rebuild the table anyway and can ignore all the other 
-                // column changes
-                columnChanges = null;
-            }
-            else if ((change instanceof ColumnChange) && (columnChanges != null))
-            {
-                // we gather all changed columns because we can use the ALTER TABLE ALTER COLUMN
-                // statement for them
-                columnChanges.add(change);
-            }
-        }
-        if (columnChanges != null)
-        {
-            HashSet processedColumns = new HashSet();
-
-            for (Iterator changeIt = columnChanges.iterator(); changeIt.hasNext();)
-            {
-                ColumnChange change       = (ColumnChange)changeIt.next();
-                Column       sourceColumn = change.getChangedColumn();
-                Column       targetColumn = targetTable.findColumn(sourceColumn.getName(), getPlatform().isDelimitedIdentifierModeOn());
-
-                if (!processedColumns.contains(targetColumn))
-                {
-                    processColumnChange(sourceTable,
-                                        targetTable,
-                                        sourceColumn,
-                                        targetColumn,
-                                        (change instanceof ColumnDataTypeChange) || (change instanceof ColumnSizeChange));
-                    processedColumns.add(targetColumn);
-                }
-                changes.remove(change);
-                change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
-            }
-        }
-        // Finally we add primary keys
-        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
-        {
-            TableChange change = (TableChange)changeIt.next();
-
-            if (change instanceof AddPrimaryKeyChange)
-            {
-                processChange(currentModel, desiredModel, (AddPrimaryKeyChange)change);
-                changeIt.remove();
-            }
-            else if (change instanceof PrimaryKeyChange)
-            {
-                PrimaryKeyChange    pkChange    = (PrimaryKeyChange)change;
-                AddPrimaryKeyChange addPkChange = new AddPrimaryKeyChange(pkChange.getChangedTable(),
-                                                                          pkChange.getNewPrimaryKeyColumns());
-
-                processChange(currentModel, desiredModel, addPkChange);
-                changeIt.remove();
-            }
-        }
-    }
-
-    /**
-     * Processes the addition of a column to a table.
-     * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
-     */
-    protected void processChange(Database        currentModel,
-                                 Database        desiredModel,
-                                 AddColumnChange change) throws IOException
+    public void addColumn(Table table, Column newColumn) throws IOException
     {
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(change.getChangedTable()));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("ADD ");
-        writeColumn(change.getChangedTable(), change.getNewColumn());
+        writeColumn(table, newColumn);
         printEndOfStatement();
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
     }
 
     /**
-     * Processes the removal of a column from a table.
+     * Generates the SQL to drop a column from a table.
      * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
-     */
-    protected void processChange(Database           currentModel,
-                                 Database           desiredModel,
-                                 RemoveColumnChange change) throws IOException
+     * @param table  The table where to drop the column from
+     * @param column The column to drop
+     */
+    public void dropColumn(Table table, Column column) throws IOException
     {
+        if (!StringUtils.isEmpty(column.getDefaultValue()))
+        {
+            writeDropConstraintStatement(table, column, "D");
+        }
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(change.getChangedTable()));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("DROP COLUMN ");
-        printIdentifier(getColumnName(change.getChangedColumn()));
+        printIdentifier(getColumnName(column));
         printEndOfStatement();
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
     }
 
     /**
-     * Processes the removal of a primary key from a table.
+     * Writes the SQL for dropping the primary key of the given table.
      * 
-     * @param currentModel The current database schema
-     * @param desiredModel The desired database schema
-     * @param change       The change object
-     */
-    protected void processChange(Database               currentModel,
-                                 Database               desiredModel,
-                                 RemovePrimaryKeyChange change) throws IOException
-    {
-        // TODO: this would be easier when named primary keys are supported
-        //       because then we can use ALTER TABLE DROP
-        String tableName         = getTableName(change.getChangedTable());
-        String tableNameVar      = "tn" + createUniqueIdentifier();
-        String constraintNameVar = "cn" + createUniqueIdentifier();
-
-        println("BEGIN");
-        println("  DECLARE @" + tableNameVar + " nvarchar(256), @" + constraintNameVar + " nvarchar(256)");
-        println("  DECLARE refcursor CURSOR FOR");
-        println("  SELECT object_name(objs.parent_obj) tablename, objs.name constraintname");
-        println("    FROM sysobjects objs JOIN sysconstraints cons ON objs.id = cons.constid");
-        print("    WHERE objs.xtype = 'PK' AND object_name(objs.parent_obj) = ");
-        printAlwaysSingleQuotedIdentifier(tableName);
-        println("  OPEN refcursor");
-        println("  FETCH NEXT FROM refcursor INTO @" + tableNameVar + ", @" + constraintNameVar);
-        println("  WHILE @@FETCH_STATUS = 0");
-        println("    BEGIN");
-        println("      EXEC ('ALTER TABLE '+@" + tableNameVar + "+' DROP CONSTRAINT '+@" + constraintNameVar + ")");
-        println("      FETCH NEXT FROM refcursor INTO @" + tableNameVar + ", @" + constraintNameVar);
-        println("    END");
-        println("  CLOSE refcursor");
-        println("  DEALLOCATE refcursor");
-        print("END");
-        printEndOfStatement();
-        change.apply(currentModel, getPlatform().isDelimitedIdentifierModeOn());
+     * @param table The table
+     */
+    public void dropPrimaryKey(Table table) throws IOException
+    {
+        // this would be easier if named primary keys are supported
+        // because for named pks we could use ALTER TABLE DROP
+        writeDropConstraintStatement(table, null, "PK");
     }
 
     /**
-     * Processes a change to a column.
+     * Writes the SQL to recreate a column, e.g. using a different type or similar.
      * 
-     * @param sourceTable  The current table
-     * @param targetTable  The desired table
-     * @param sourceColumn The current column
-     * @param targetColumn The desired column
-     * @param typeChange   Whether this is a type change
-     */
-    protected void processColumnChange(Table   sourceTable,
-                                       Table   targetTable,
-                                       Column  sourceColumn,
-                                       Column  targetColumn,
-                                       boolean typeChange) throws IOException
-    {
-        boolean hasDefault       = sourceColumn.getParsedDefaultValue() != null;
-        boolean shallHaveDefault = targetColumn.getParsedDefaultValue() != null;
-        String  newDefault       = targetColumn.getDefaultValue();
+     * @param table     The table
+     * @param curColumn The current column definition
+     * @param newColumn The new column definition
+     */
+    public void recreateColumn(Table table, Column curColumn, Column newColumn) throws IOException
+    {
+        boolean hasDefault       = curColumn.getParsedDefaultValue() != null;
+        boolean shallHaveDefault = newColumn.getParsedDefaultValue() != null;
+        String  newDefault       = newColumn.getDefaultValue();
 
         // Sql Server does not like it if there is a default spec in the ALTER TABLE ALTER COLUMN
         // statement; thus we have to change the default manually
         if (newDefault != null)
         {
-            targetColumn.setDefaultValue(null);
+            newColumn.setDefaultValue(null);
         }
         if (hasDefault)
         {
             // we're dropping the old default
-            String tableName         = getTableName(sourceTable);
-            String columnName        = getColumnName(sourceColumn);
-            String tableNameVar      = "tn" + createUniqueIdentifier();
-            String constraintNameVar = "cn" + createUniqueIdentifier();
-
-            println("BEGIN");
-            println("  DECLARE @" + tableNameVar + " nvarchar(256), @" + constraintNameVar + " nvarchar(256)");
-            println("  DECLARE refcursor CURSOR FOR");
-            println("  SELECT object_name(objs.parent_obj) tablename, objs.name constraintname");
-            println("    FROM sysobjects objs JOIN sysconstraints cons ON objs.id = cons.constid");
-            println("    WHERE objs.xtype = 'D' AND");
-            print("          cons.colid = (SELECT colid FROM syscolumns WHERE id = object_id(");
-            printAlwaysSingleQuotedIdentifier(tableName);
-            print(") AND name = ");
-            printAlwaysSingleQuotedIdentifier(columnName);
-            println(") AND");
-            print("          object_name(objs.parent_obj) = ");
-            printAlwaysSingleQuotedIdentifier(tableName);
-            println("  OPEN refcursor");
-            println("  FETCH NEXT FROM refcursor INTO @" + tableNameVar + ", @" + constraintNameVar);
-            println("  WHILE @@FETCH_STATUS = 0");
-            println("    BEGIN");
-            println("      EXEC ('ALTER TABLE '+@" + tableNameVar + "+' DROP CONSTRAINT '+@" + constraintNameVar + ")");
-            println("      FETCH NEXT FROM refcursor INTO @" + tableNameVar + ", @" + constraintNameVar);
-            println("    END");
-            println("  CLOSE refcursor");
-            println("  DEALLOCATE refcursor");
-            print("END");
-            printEndOfStatement();
+            writeDropConstraintStatement(table, curColumn, "D");
         }
 
         print("ALTER TABLE ");
-        printlnIdentifier(getTableName(sourceTable));
+        printlnIdentifier(getTableName(table));
         printIndent();
         print("ALTER COLUMN ");
-        writeColumn(sourceTable, targetColumn);
+        writeColumn(table, newColumn);
         printEndOfStatement();
 
         if (shallHaveDefault)
         {
-            targetColumn.setDefaultValue(newDefault);
+            newColumn.setDefaultValue(newDefault);
 
             // if the column shall have a default, then we have to add it as a constraint
             print("ALTER TABLE ");
-            printlnIdentifier(getTableName(sourceTable));
+            printlnIdentifier(getTableName(table));
             printIndent();
             print("ADD CONSTRAINT ");
-            printIdentifier(getConstraintName("DF", sourceTable, sourceColumn.getName(), null));
-            writeColumnDefaultValueStmt(sourceTable, targetColumn);
+            printIdentifier(getConstraintName("DF", table, curColumn.getName(), null));
+            writeColumnDefaultValueStmt(table, newColumn);
             print(" FOR ");
-            printIdentifier(getColumnName(sourceColumn));
+            printIdentifier(getColumnName(curColumn));
             printEndOfStatement();
         }
+    }
+
+    /**
+     * Writes the SQL to drop a constraint, e.g. a primary key or default value constraint.
+     * 
+     * @param table          The table that the constraint is on
+     * @param column         The column that the constraint is on; <code>null</code> for table-level
+     *                       constraints
+     * @param typeIdentifier The constraint type identifier as is specified for the
+     *                       <code>sysobjects</code> system table
+     */
+    protected void writeDropConstraintStatement(Table table, Column column, String typeIdentifier) throws IOException
+    {
+        String tableName         = getTableName(table);
+        String columnName        = column == null ? null : getColumnName(column);
+        String tableNameVar      = "tn" + createUniqueIdentifier();
+        String constraintNameVar = "cn" + createUniqueIdentifier();
+
+        println("BEGIN");
+        println("  DECLARE @" + tableNameVar + " nvarchar(256), @" + constraintNameVar + " nvarchar(256)");
+        println("  DECLARE refcursor CURSOR FOR");
+        println("  SELECT object_name(objs.parent_obj) tablename, objs.name constraintname");
+        println("    FROM sysobjects objs JOIN sysconstraints cons ON objs.id = cons.constid");
+        print("    WHERE objs.xtype = '");
+        print(typeIdentifier);
+        println("' AND");
+        if (columnName != null)
+        {
+            print("          cons.colid = (SELECT colid FROM syscolumns WHERE id = object_id(");
+            printAlwaysSingleQuotedIdentifier(tableName);
+            print(") AND name = ");
+            printAlwaysSingleQuotedIdentifier(columnName);
+            println(") AND");
+        }
+        print("          object_name(objs.parent_obj) = ");
+        printAlwaysSingleQuotedIdentifier(tableName);
+        println("  OPEN refcursor");
+        println("  FETCH NEXT FROM refcursor INTO @" + tableNameVar + ", @" + constraintNameVar);
+        println("  WHILE @@FETCH_STATUS = 0");
+        println("    BEGIN");
+        println("      EXEC ('ALTER TABLE '+@" + tableNameVar + "+' DROP CONSTRAINT '+@" + constraintNameVar + ")");
+        println("      FETCH NEXT FROM refcursor INTO @" + tableNameVar + ", @" + constraintNameVar);
+        println("    END");
+        println("  CLOSE refcursor");
+        println("  DEALLOCATE refcursor");
+        print("END");
+        printEndOfStatement();
     }
 }

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlModelComparator.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlModelComparator.java?rev=602807&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlModelComparator.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/mssql/MSSqlModelComparator.java Mon Dec 10 00:20:47 2007
@@ -0,0 +1,325 @@
+package org.apache.ddlutils.platform.mssql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.alteration.AddForeignKeyChange;
+import org.apache.ddlutils.alteration.AddIndexChange;
+import org.apache.ddlutils.alteration.AddPrimaryKeyChange;
+import org.apache.ddlutils.alteration.ModelComparator;
+import org.apache.ddlutils.alteration.RemoveForeignKeyChange;
+import org.apache.ddlutils.alteration.RemoveIndexChange;
+import org.apache.ddlutils.alteration.RemovePrimaryKeyChange;
+import org.apache.ddlutils.alteration.TableDefinitionChangesPredicate;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.ForeignKey;
+import org.apache.ddlutils.model.Index;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.util.StringUtils;
+
+/**
+ * A model comparator customized for Sql Server.
+ * 
+ * @version $Revision: $
+ */
+public class MSSqlModelComparator extends ModelComparator
+{
+    /**
+     * Creates a new Sql Server model comparator object.
+     * 
+     * @param platformInfo            The platform info
+     * @param tableDefChangePredicate The predicate that defines whether tables changes are supported
+     *                                by the platform or not; all changes are supported if this is null
+     * @param caseSensitive           Whether comparison is case sensitive
+     */
+    public MSSqlModelComparator(PlatformInfo                    platformInfo,
+                                TableDefinitionChangesPredicate tableDefChangePredicate,
+                                boolean                         caseSensitive)
+    {
+        super(platformInfo, tableDefChangePredicate, caseSensitive);
+        setGeneratePrimaryKeyChanges(false);
+        setCanDropPrimaryKeyColumns(false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected List checkForPrimaryKeyChanges(Database sourceModel,
+                                             Table    sourceTable,
+                                             Database intermediateModel,
+                                             Table    intermediateTable,
+                                             Database targetModel,
+                                             Table    targetTable)
+    {
+        List changes = super.checkForPrimaryKeyChanges(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable);
+
+        // now we add pk changes if one of the pk columns was changed
+        // we only need to do this if there is no other pk change (which can only be a remove or add change or both)
+        if (changes.isEmpty())
+        {
+            List columns = getRelevantChangedColumns(sourceTable, targetTable);
+
+            for (Iterator it = columns.iterator(); it.hasNext();)
+            {
+                Column targetColumn = (Column)it.next();
+
+                if (targetColumn.isPrimaryKey())
+                {
+                    changes.add(new RemovePrimaryKeyChange(sourceTable.getName()));
+                    changes.add(new AddPrimaryKeyChange(sourceTable.getName(), sourceTable.getPrimaryKeyColumnNames()));
+                    break;
+                }
+            }
+        }
+        return changes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected List checkForRemovedIndexes(Database sourceModel,
+                                          Table    sourceTable,
+                                          Database intermediateModel,
+                                          Table    intermediateTable,
+                                          Database targetModel,
+                                          Table    targetTable)
+    {
+        List    changes           = super.checkForRemovedIndexes(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable);
+        Index[] targetIndexes     = targetTable.getIndices();
+        List    additionalChanges = new ArrayList();
+
+        // removing all indexes that are maintained and that use a changed column
+        if (targetIndexes.length > 0)
+        {
+            List columns = getRelevantChangedColumns(sourceTable, targetTable);
+
+            if (!columns.isEmpty())
+            {
+                for (int indexIdx = 0; indexIdx < targetIndexes.length; indexIdx++)
+                {
+                    Index sourceIndex = findCorrespondingIndex(sourceTable, targetIndexes[indexIdx]);
+
+                    if (sourceIndex != null)
+                    {
+                        for (Iterator columnIt = columns.iterator(); columnIt.hasNext();)
+                        {
+                            Column targetColumn = (Column)columnIt.next();
+
+                            if (targetIndexes[indexIdx].hasColumn(targetColumn))
+                            {
+                                additionalChanges.add(new RemoveIndexChange(intermediateTable.getName(), targetIndexes[indexIdx]));
+                                break;
+                            }
+                        }
+                    }
+                }
+                for (Iterator changeIt = additionalChanges.iterator(); changeIt.hasNext();)
+                {
+                    ((RemoveIndexChange)changeIt.next()).apply(intermediateModel, isCaseSensitive());
+                }
+                changes.addAll(additionalChanges);
+            }
+        }
+        return changes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected List checkForAddedIndexes(Database sourceModel,
+                                        Table    sourceTable,
+                                        Database intermediateModel,
+                                        Table    intermediateTable,
+                                        Database targetModel,
+                                        Table    targetTable)
+    {
+        List    changes           = super.checkForAddedIndexes(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable);
+        Index[] targetIndexes     = targetTable.getIndices();
+        List    additionalChanges = new ArrayList();
+
+        // re-adding all indexes that are maintained and that use a changed column
+        if (targetIndexes.length > 0)
+        {
+            for (int indexIdx = 0; indexIdx < targetIndexes.length; indexIdx++)
+            {
+                Index sourceIndex       = findCorrespondingIndex(sourceTable, targetIndexes[indexIdx]);
+                Index intermediateIndex = findCorrespondingIndex(intermediateTable, targetIndexes[indexIdx]);
+
+                if ((sourceIndex != null) && (intermediateIndex == null))
+                {
+                    additionalChanges.add(new AddIndexChange(intermediateTable.getName(), targetIndexes[indexIdx]));
+                }
+            }
+            for (Iterator changeIt = additionalChanges.iterator(); changeIt.hasNext();)
+            {
+                ((AddIndexChange)changeIt.next()).apply(intermediateModel, isCaseSensitive());
+            }
+            changes.addAll(additionalChanges);
+        }
+        return changes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected List checkForRemovedForeignKeys(Database sourceModel,
+                                              Database intermediateModel,
+                                              Database targetModel)
+    {
+        List changes           = super.checkForRemovedForeignKeys(sourceModel, intermediateModel, targetModel);
+        List additionalChanges = new ArrayList();
+
+        // removing all foreign keys that are maintained and that use a changed column
+        for (int tableIdx = 0; tableIdx < targetModel.getTableCount(); tableIdx++)
+        {
+            Table targetTable = targetModel.getTable(tableIdx);
+            Table sourceTable = sourceModel.findTable(targetTable.getName(), isCaseSensitive());
+
+            if (sourceTable != null)
+            {
+                List columns = getRelevantChangedColumns(sourceTable, targetTable);
+
+                if (!columns.isEmpty())
+                {
+                    for (int fkIdx = 0; fkIdx < targetTable.getForeignKeyCount(); fkIdx++)
+                    {
+                        ForeignKey targetFk = targetTable.getForeignKey(fkIdx);
+                        ForeignKey sourceFk = findCorrespondingForeignKey(sourceTable, targetFk);
+
+                        if (sourceFk != null)
+                        {
+                            for (Iterator columnIt = columns.iterator(); columnIt.hasNext();)
+                            {
+                                Column targetColumn = (Column)columnIt.next();
+
+                                if (targetFk.hasLocalColumn(targetColumn) || targetFk.hasForeignColumn(targetColumn))
+                                {
+                                    additionalChanges.add(new RemoveForeignKeyChange(sourceTable.getName(), targetFk));
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        for (Iterator changeIt = additionalChanges.iterator(); changeIt.hasNext();)
+        {
+            ((RemoveForeignKeyChange)changeIt.next()).apply(intermediateModel, isCaseSensitive());
+        }
+        changes.addAll(additionalChanges);
+        return changes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected List checkForAddedForeignKeys(Database sourceModel,
+                                            Database intermediateModel,
+                                            Database targetModel)
+    {
+        List changes           = super.checkForAddedForeignKeys(sourceModel, intermediateModel, targetModel);
+        List additionalChanges = new ArrayList();
+
+        // re-adding all foreign keys that are maintained and that use a changed column
+        for (int tableIdx = 0; tableIdx < targetModel.getTableCount(); tableIdx++)
+        {
+            Table targetTable       = targetModel.getTable(tableIdx);
+            Table sourceTable       = sourceModel.findTable(targetTable.getName(), isCaseSensitive());
+            Table intermediateTable = intermediateModel.findTable(targetTable.getName(), isCaseSensitive());
+
+            if (sourceTable != null)
+            {
+                for (int fkIdx = 0; fkIdx < targetTable.getForeignKeyCount(); fkIdx++)
+                {
+                    ForeignKey targetFk       = targetTable.getForeignKey(fkIdx);
+                    ForeignKey sourceFk       = findCorrespondingForeignKey(sourceTable, targetFk);
+                    ForeignKey intermediateFk = findCorrespondingForeignKey(intermediateTable, targetFk);
+
+                    if ((sourceFk != null) && (intermediateFk == null))
+                    {
+                        additionalChanges.add(new AddForeignKeyChange(intermediateTable.getName(), targetFk));
+                    }
+                }
+            }
+        }
+        for (Iterator changeIt = additionalChanges.iterator(); changeIt.hasNext();)
+        {
+            ((AddForeignKeyChange)changeIt.next()).apply(intermediateModel, isCaseSensitive());
+        }
+        changes.addAll(additionalChanges);
+        return changes;
+    }
+
+    /**
+     * Returns all columns that are changed in a way that makes it necessary to recreate foreign keys and
+     * indexes using them.
+     *  
+     * @param sourceTable The source table
+     * @param targetTable The target table
+     * @return The columns (from the target table)
+     */
+    private List getRelevantChangedColumns(Table sourceTable, Table targetTable)
+    {
+        List result = new ArrayList();
+
+        for (int columnIdx = 0; columnIdx < targetTable.getColumnCount(); columnIdx++)
+        {
+            Column targetColumn = targetTable.getColumn(columnIdx);
+            Column sourceColumn = sourceTable.findColumn(targetColumn.getName(), isCaseSensitive());
+
+            if (sourceColumn != null)
+            {
+                boolean hasChange      = false;
+                int     targetTypeCode = getPlatformInfo().getTargetJdbcType(targetColumn.getTypeCode());
+                boolean sizeMatters    = getPlatformInfo().hasSize(targetTypeCode);
+                boolean scaleMatters   = getPlatformInfo().hasPrecisionAndScale(targetTypeCode);
+
+                if (targetTypeCode != sourceColumn.getTypeCode())
+                {
+                    hasChange = true;
+                }
+                else
+                {
+                    if (sizeMatters && !StringUtils.equals(sourceColumn.getSize(), targetColumn.getSize()))
+                    {
+                        hasChange = true;
+                    }
+                    else if (scaleMatters &&
+                             (!StringUtils.equals(sourceColumn.getSize(), targetColumn.getSize()) ||
+                              (sourceColumn.getScale() != targetColumn.getScale())))
+                    {
+                        hasChange = true;
+                    }
+                }
+                if (hasChange)
+                {
+                    result.add(targetColumn);
+                }
+            }
+        }
+        return result;
+    }
+}



Mime
View raw message