You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ddlutils-dev@db.apache.org by to...@apache.org on 2007/12/10 09:21:39 UTC

svn commit: r602807 [2/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...

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java Mon Dec 10 00:20:47 2007
@@ -23,15 +23,16 @@
 import java.util.HashMap;
 import java.util.List;
 
-import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.model.CloneHelper;
 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;
 
 /**
  * Compares two database models and creates change objects that express how to
@@ -39,8 +40,6 @@
  * are changed in the process, however, it is also assumed that the models do not
  * change in between.
  * 
- * TODO: Add support and tests for the change of the column order 
- * 
  * @version $Revision: $
  */
 public class ModelComparator
@@ -50,19 +49,79 @@
 
     /** The platform information. */
     private PlatformInfo _platformInfo;
+    /** The predicate that defines which changes are supported by the platform. */
+    private TableDefinitionChangesPredicate _tableDefCangePredicate;
+    /** The object clone helper. */
+    private CloneHelper _cloneHelper = new CloneHelper();
     /** Whether comparison is case sensitive. */
     private boolean _caseSensitive;
+    /** Whether the comparator should generate {@link PrimaryKeyChange} objects. */
+    private boolean _generatePrimaryKeyChanges = true;
+    /** Whether {@link RemoveColumnChange} objects for primary key columns are enough or
+        additional primary key change objects are necessary. */
+    private boolean _canDropPrimaryKeyColumns = true;
 
     /**
      * Creates a new model comparator object.
      * 
-     * @param platformInfo  The platform info
-     * @param caseSensitive Whether comparison is case sensitive
+     * @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 ModelComparator(PlatformInfo                    platformInfo,
+                           TableDefinitionChangesPredicate tableDefChangePredicate,
+                           boolean                         caseSensitive)
+    {
+        _platformInfo           = platformInfo;
+        _caseSensitive          = caseSensitive;
+        _tableDefCangePredicate = tableDefChangePredicate;
+    }
+
+    /**
+     * Specifies whether the comparator should generate {@link PrimaryKeyChange} objects or a
+     * pair of {@link RemovePrimaryKeyChange} and {@link AddPrimaryKeyChange} objects instead.
+     * The default value is <code>true</code>.
+     * 
+     * @param generatePrimaryKeyChanges Whether to create {@link PrimaryKeyChange} objects
+     */
+    public void setGeneratePrimaryKeyChanges(boolean generatePrimaryKeyChanges)
+    {
+        _generatePrimaryKeyChanges = generatePrimaryKeyChanges;
+    }
+
+    /**
+     * Specifies whether the {@link RemoveColumnChange} are fine even for primary key columns.
+     * If the platform cannot drop primary key columns, set this to <code>false</code> and the
+     * comparator will create additional primary key changes. 
+     * The default value is <code>true</code>.
+     * 
+     * @param canDropPrimaryKeyColumns Whether {@link RemoveColumnChange} objecs for primary
+     *                                 key columns are ok 
+     */
+    public void setCanDropPrimaryKeyColumns(boolean canDropPrimaryKeyColumns)
+    {
+        _canDropPrimaryKeyColumns = canDropPrimaryKeyColumns;
+    }
+
+    /**
+     * Returns the info object for the platform.
+     * 
+     * @return The platform info object
      */
-    public ModelComparator(PlatformInfo platformInfo, boolean caseSensitive)
+    protected PlatformInfo getPlatformInfo()
     {
-        _platformInfo  = platformInfo;
-        _caseSensitive = caseSensitive;
+        return _platformInfo;
+    }
+
+    /**
+     * Determines whether comparison should be case sensitive.
+     * 
+     * @return <code>true</code> if case matters
+     */
+    protected boolean isCaseSensitive()
+    {
+        return _caseSensitive;
     }
 
     /**
@@ -75,217 +134,661 @@
      */
     public List compare(Database sourceModel, Database targetModel)
     {
+        Database intermediateModel = _cloneHelper.clone(sourceModel);
+
+        return compareModels(sourceModel, intermediateModel, targetModel);
+    }
+
+    /**
+     * Compares the given source and target models and creates change objects to get from
+     * the source to the target one. These changes will be applied to the given
+     * intermediate model (the other two won't be changed), so that it will be equal to
+     * the target model after this model has finished.
+     * 
+     * @param sourceModel       The source model
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param targetModel       The target model
+     * @return The changes
+     */
+    protected List compareModels(Database sourceModel,
+                                 Database intermediateModel,
+                                 Database targetModel)
+    {
         ArrayList changes = new ArrayList();
 
-        for (int tableIdx = 0; tableIdx < targetModel.getTableCount(); tableIdx++)
+        changes.addAll(checkForRemovedForeignKeys(sourceModel, intermediateModel, targetModel));
+        changes.addAll(checkForRemovedTables(sourceModel, intermediateModel, targetModel));
+
+        for (int tableIdx = 0; tableIdx < intermediateModel.getTableCount(); tableIdx++)
         {
-            Table targetTable = targetModel.getTable(tableIdx);
-            Table sourceTable = sourceModel.findTable(targetTable.getName(), _caseSensitive);
+            Table intermediateTable = intermediateModel.getTable(tableIdx);
+            Table sourceTable       = sourceModel.findTable(intermediateTable.getName(), _caseSensitive);
+            Table targetTable       = targetModel.findTable(intermediateTable.getName(), _caseSensitive);
+            List  tableChanges      = compareTables(sourceModel, sourceTable,
+                                                    intermediateModel, intermediateTable,
+                                                    targetModel, targetTable);
+
+            changes.addAll(tableChanges);
+        }
 
-            if (sourceTable == null)
+        changes.addAll(checkForAddedTables(sourceModel, intermediateModel, targetModel));
+        changes.addAll(checkForAddedForeignKeys(sourceModel, intermediateModel, targetModel));
+        return changes;
+    }
+
+    /**
+     * Creates change objects for foreign keys that are present in the given source model but are no longer in the target
+     * model, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param targetModel       The target model
+     * @return The changes
+     */
+    protected List checkForRemovedForeignKeys(Database sourceModel,
+                                              Database intermediateModel,
+                                              Database targetModel)
+    {
+        List changes = new ArrayList();
+
+        for (int tableIdx = 0; tableIdx < intermediateModel.getTableCount(); tableIdx++)
+        {
+            Table        intermediateTable = intermediateModel.getTable(tableIdx);
+            Table        targetTable       = targetModel.findTable(intermediateTable.getName(), _caseSensitive);
+            ForeignKey[] intermediateFks   = intermediateTable.getForeignKeys();
+
+            // Dropping foreign keys from tables to be removed might not be necessary, but some databases might require it
+            for (int fkIdx = 0; fkIdx < intermediateFks.length; fkIdx++)
             {
-                if (_log.isInfoEnabled())
-                {
-                    _log.info("Table " + targetTable.getName() + " needs to be added");
-                }
-                changes.add(new AddTableChange(targetTable));
-                for (int fkIdx = 0; fkIdx < targetTable.getForeignKeyCount(); fkIdx++)
+                ForeignKey sourceFk = intermediateFks[fkIdx];
+                ForeignKey targetFk = targetTable == null ? null : findCorrespondingForeignKey(targetTable, sourceFk);
+
+                if (targetFk == null)
                 {
-                    // we have to use target table's definition here because the
-                    // complete table is new
-                    changes.add(new AddForeignKeyChange(targetTable, targetTable.getForeignKey(fkIdx)));
+                    if (_log.isInfoEnabled())
+                    {
+                        _log.info("Foreign key " + sourceFk + " needs to be removed from table " + intermediateTable.getName());
+                    }
+
+                    RemoveForeignKeyChange fkChange = new RemoveForeignKeyChange(intermediateTable.getName(), sourceFk);
+
+                    changes.add(fkChange);
+                    fkChange.apply(intermediateModel, _caseSensitive);
                 }
             }
-            else
+        }
+        return changes;
+    }
+
+    /**
+     * Creates change objects for foreign keys that are not present in the given source model but are in the target
+     * model, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param targetModel       The target model
+     * @return The changes
+     */
+    protected List checkForAddedForeignKeys(Database sourceModel,
+                                            Database intermediateModel,
+                                            Database targetModel)
+    {
+        List changes = new ArrayList();
+
+        for (int tableIdx = 0; tableIdx < targetModel.getTableCount(); tableIdx++)
+        {
+            Table targetTable       = targetModel.getTable(tableIdx);
+            Table intermediateTable = intermediateModel.findTable(targetTable.getName(), _caseSensitive);
+
+            for (int fkIdx = 0; fkIdx < targetTable.getForeignKeyCount(); fkIdx++)
             {
-                changes.addAll(compareTables(sourceModel, sourceTable, targetModel, targetTable));
+                ForeignKey targetFk       = targetTable.getForeignKey(fkIdx);
+                ForeignKey intermediateFk = findCorrespondingForeignKey(intermediateTable, targetFk);
+
+                if (intermediateFk == null)
+                {
+                    if (_log.isInfoEnabled())
+                    {
+                        _log.info("Foreign key " + targetFk + " needs to be added to table " + intermediateTable.getName());
+                    }
+
+                    intermediateFk = _cloneHelper.clone(targetFk, intermediateTable, intermediateModel, _caseSensitive);
+
+                    AddForeignKeyChange fkChange = new AddForeignKeyChange(intermediateTable.getName(), intermediateFk);
+
+                    changes.add(fkChange);
+                    fkChange.apply(intermediateModel, _caseSensitive);
+                }
             }
         }
+        return changes;
+    }
+
+    /**
+     * Creates change objects for tables that are present in the given source model but are no longer in the target
+     * model, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param targetModel       The target model
+     * @return The changes
+     */
+    protected List checkForRemovedTables(Database sourceModel,
+                                         Database intermediateModel,
+                                         Database targetModel)
+    {
+        List    changes            = new ArrayList();
+        Table[] intermediateTables = intermediateModel.getTables();
 
-        for (int tableIdx = 0; tableIdx < sourceModel.getTableCount(); tableIdx++)
+        for (int tableIdx = 0; tableIdx < intermediateTables.length; tableIdx++)
         {
-            Table sourceTable = sourceModel.getTable(tableIdx);
-            Table targetTable = targetModel.findTable(sourceTable.getName(), _caseSensitive);
+            Table intermediateTable = intermediateTables[tableIdx];
+            Table targetTable       = targetModel.findTable(intermediateTable.getName(), _caseSensitive);
 
-            if ((targetTable == null) && (sourceTable.getName() != null) && (sourceTable.getName().length() > 0))
+            if (targetTable == null)
             {
                 if (_log.isInfoEnabled())
                 {
-                    _log.info("Table " + sourceTable.getName() + " needs to be removed");
-                }
-                changes.add(new RemoveTableChange(sourceTable));
-                // we assume that the target model is sound, ie. that there are no longer any foreign
-                // keys to this table in the target model; thus we already have removeFK changes for
-                // these from the compareTables method and we only need to create changes for the fks
-                // originating from this table
-                for (int fkIdx = 0; fkIdx < sourceTable.getForeignKeyCount(); fkIdx++)
-                {
-                    changes.add(new RemoveForeignKeyChange(sourceTable, sourceTable.getForeignKey(fkIdx)));
+                    _log.info("Table " + intermediateTable.getName() + " needs to be removed");
                 }
+
+                RemoveTableChange tableChange = new RemoveTableChange(intermediateTable.getName());
+
+                changes.add(tableChange);
+                tableChange.apply(intermediateModel, _caseSensitive);
             }
         }
         return changes;
     }
 
     /**
-     * Compares the two tables and returns the changes necessary to create the second
-     * table from the first one.
-     *  
-     * @param sourceModel The source model which contains the source table
-     * @param sourceTable The source table
-     * @param targetModel The target model which contains the target table
-     * @param targetTable The target table
+     * Creates change objects for tables that are not present in the given source model but are in the target
+     * model, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param targetModel       The target model
      * @return The changes
      */
-    public List compareTables(Database sourceModel,
-                              Table    sourceTable,
-                              Database targetModel,
-                              Table    targetTable)
+    protected List checkForAddedTables(Database sourceModel,
+                                       Database intermediateModel,
+                                       Database targetModel)
     {
-        ArrayList changes = new ArrayList();
+        List changes = new ArrayList();
 
-        for (int fkIdx = 0; fkIdx < sourceTable.getForeignKeyCount(); fkIdx++)
+        for (int tableIdx = 0; tableIdx < targetModel.getTableCount(); tableIdx++)
         {
-            ForeignKey sourceFk = sourceTable.getForeignKey(fkIdx);
-            ForeignKey targetFk = findCorrespondingForeignKey(targetTable, sourceFk);
+            Table targetTable       = targetModel.getTable(tableIdx);
+            Table intermediateTable = intermediateModel.findTable(targetTable.getName(), _caseSensitive);
 
-            if (targetFk == null)
+            if (intermediateTable == null)
             {
                 if (_log.isInfoEnabled())
                 {
-                    _log.info("Foreign key " + sourceFk + " needs to be removed from table " + sourceTable.getName());
+                    _log.info("Table " + targetTable.getName() + " needs to be added");
                 }
-                changes.add(new RemoveForeignKeyChange(sourceTable, sourceFk));
+
+                // we're using a clone of the target table, and remove all foreign
+                // keys as these will be added later
+                intermediateTable = _cloneHelper.clone(targetTable, true, false, intermediateModel, _caseSensitive);
+
+                AddTableChange tableChange = new AddTableChange(intermediateTable);
+
+                changes.add(tableChange);
+                tableChange.apply(intermediateModel, _caseSensitive);
             }
         }
+        return changes;
+    }
 
-        for (int fkIdx = 0; fkIdx < targetTable.getForeignKeyCount(); fkIdx++)
-        {
-            ForeignKey targetFk = targetTable.getForeignKey(fkIdx);
-            ForeignKey sourceFk = findCorrespondingForeignKey(sourceTable, targetFk);
+    /**
+     * Compares the two tables and returns the changes necessary to create the second
+     * table from the first one.
+     *  
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to which the changes will be applied incrementally
+     * @param intermediateTable The table corresponding to the source table in the intermediate model
+     * @param targetModel       The target model which contains the target table
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List compareTables(Database sourceModel,
+                                 Table    sourceTable,
+                                 Database intermediateModel,
+                                 Table    intermediateTable,
+                                 Database targetModel,
+                                 Table    targetTable)
+    {
+        ArrayList changes = new ArrayList();
+
+        changes.addAll(checkForRemovedIndexes(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+
+        ArrayList tableDefinitionChanges = new ArrayList();
+        Table     tmpTable               = _cloneHelper.clone(intermediateTable, true, false, intermediateModel, _caseSensitive);
 
-            if (sourceFk == null)
+        tableDefinitionChanges.addAll(checkForRemovedColumns(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+        tableDefinitionChanges.addAll(checkForChangeOfColumnOrder(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+        tableDefinitionChanges.addAll(checkForChangedColumns(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+        tableDefinitionChanges.addAll(checkForAddedColumns(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+        tableDefinitionChanges.addAll(checkForPrimaryKeyChanges(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+
+        if (!tableDefinitionChanges.isEmpty())
+        {
+            if ((_tableDefCangePredicate == null) || _tableDefCangePredicate.areSupported(tmpTable, tableDefinitionChanges))
             {
-                if (_log.isInfoEnabled())
+                changes.addAll(tableDefinitionChanges);
+            }
+            else
+            {
+                // we need to recreate the table; for this to work we need to remove foreign keys to and from the table
+                // however, we don't have to add them back here as there is a check for added foreign keys/indexes
+                // later on anyways
+                // we also don't have to drop indexes on the original table
+
+                ForeignKey[] fks = intermediateTable.getForeignKeys();
+
+                for (int fkIdx = 0; fkIdx < fks.length; fkIdx++)
                 {
-                    _log.info("Foreign key " + targetFk + " needs to be created for table " + sourceTable.getName());
+                    RemoveForeignKeyChange fkChange = new RemoveForeignKeyChange(intermediateTable.getName(), fks[fkIdx]);
+
+                    changes.add(fkChange);
+                    fkChange.apply(intermediateModel, _caseSensitive);
+                }
+                for (int tableIdx = 0; tableIdx < intermediateModel.getTableCount(); tableIdx++)
+                {
+                    Table curTable = intermediateModel.getTable(tableIdx);
+
+                    if (curTable != intermediateTable)
+                    {
+                        ForeignKey[] curFks = curTable.getForeignKeys();
+
+                        for (int fkIdx = 0; fkIdx < curFks.length; fkIdx++)
+                        {
+                            if ((_caseSensitive  && curFks[fkIdx].getForeignTableName().equals(intermediateTable.getName())) ||
+                                (!_caseSensitive && curFks[fkIdx].getForeignTableName().equalsIgnoreCase(intermediateTable.getName())))
+                            {
+                                RemoveForeignKeyChange fkChange = new RemoveForeignKeyChange(curTable.getName(), curFks[fkIdx]);
+    
+                                changes.add(fkChange);
+                                fkChange.apply(intermediateModel, _caseSensitive);
+                            }
+                        }
+                    }
                 }
-                // we have to use the target table here because the foreign key might
-                // reference a new column
-                changes.add(new AddForeignKeyChange(targetTable, targetFk));
+
+                RecreateTableChange tableChange =  new RecreateTableChange(intermediateTable.getName(),
+                                                                           intermediateTable,
+                                                                           new ArrayList(tableDefinitionChanges));
+
+                changes.add(tableChange);
+                tableChange.apply(intermediateModel, _caseSensitive);
             }
         }
+        
+        changes.addAll(checkForAddedIndexes(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));
+
+        return changes;
+    }
+
+    /**
+     * Returns the names of the columns in the intermediate table corresponding to the given column objects.
+     * 
+     * @param columns           The column objects
+     * @param intermediateTable The intermediate table
+     * @return The column names
+     */
+    protected String[] getIntermediateColumnNamesFor(Column[] columns, Table intermediateTable)
+    {
+        String[] result = new String[columns.length];
 
-        for (int indexIdx = 0; indexIdx < sourceTable.getIndexCount(); indexIdx++)
+        for (int idx = 0; idx < columns.length; idx++)
         {
-            Index sourceIndex = sourceTable.getIndex(indexIdx);
+            result[idx] = intermediateTable.findColumn(columns[idx].getName(), _caseSensitive).getName();
+        }
+        return result;
+    }
+
+    /**
+     * Creates change objects for indexes that are present in the given source table but are no longer in the target
+     * table, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForRemovedIndexes(Database sourceModel,
+                                          Table    sourceTable,
+                                          Database intermediateModel,
+                                          Table    intermediateTable,
+                                          Database targetModel,
+                                          Table    targetTable)
+    {
+        List    changes = new ArrayList();
+        Index[] indexes = intermediateTable.getIndices();
+
+        for (int indexIdx = 0; indexIdx < indexes.length; indexIdx++)
+        {
+            Index sourceIndex = indexes[indexIdx];
             Index targetIndex = findCorrespondingIndex(targetTable, sourceIndex);
 
             if (targetIndex == null)
             {
                 if (_log.isInfoEnabled())
                 {
-                    _log.info("Index " + sourceIndex.getName() + " needs to be removed from table " + sourceTable.getName());
+                    _log.info("Index " + sourceIndex.getName() + " needs to be removed from table " + intermediateTable.getName());
                 }
-                changes.add(new RemoveIndexChange(sourceTable, sourceIndex));
+
+                RemoveIndexChange change = new RemoveIndexChange(intermediateTable.getName(), sourceIndex);
+
+                changes.add(change);
+                change.apply(intermediateModel, _caseSensitive);
             }
         }
+        return changes;
+    }
+
+    /**
+     * Creates change objects for indexes that are not present in the given source table but are in the target
+     * table, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForAddedIndexes(Database sourceModel,
+                                        Table    sourceTable,
+                                        Database intermediateModel,
+                                        Table    intermediateTable,
+                                        Database targetModel,
+                                        Table    targetTable)
+    {
+        List changes = new ArrayList();
+
         for (int indexIdx = 0; indexIdx < targetTable.getIndexCount(); indexIdx++)
         {
             Index targetIndex = targetTable.getIndex(indexIdx);
-            Index sourceIndex = findCorrespondingIndex(sourceTable, targetIndex);
+            Index sourceIndex = findCorrespondingIndex(intermediateTable, targetIndex);
 
             if (sourceIndex == null)
             {
                 if (_log.isInfoEnabled())
                 {
-                    _log.info("Index " + targetIndex.getName() + " needs to be created for table " + sourceTable.getName());
+                    _log.info("Index " + targetIndex.getName() + " needs to be created for table " + intermediateTable.getName());
                 }
-                // we have to use the target table here because the index might
-                // reference a new column
-                changes.add(new AddIndexChange(targetTable, targetIndex));
+
+                Index          clonedIndex = _cloneHelper.clone(targetIndex, intermediateTable, _caseSensitive);
+                AddIndexChange change      = new AddIndexChange(intermediateTable.getName(), clonedIndex);
+
+                changes.add(change);
+                change.apply(intermediateModel, _caseSensitive);
             }
         }
+        return changes;
+    }
 
-        HashMap addColumnChanges = new HashMap();
+    /**
+     * Checks for changes in the column order between the given source and target table, creates change objects for these and
+     * applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForChangeOfColumnOrder(Database sourceModel,
+                                               Table    sourceTable,
+                                               Database intermediateModel,
+                                               Table    intermediateTable,
+                                               Database targetModel,
+                                               Table    targetTable)
+    {
+        List changes       = new ArrayList();
+        List targetOrder   = new ArrayList();
+        int  numChangedPKs = 0;
 
         for (int columnIdx = 0; columnIdx < targetTable.getColumnCount(); columnIdx++)
         {
             Column targetColumn = targetTable.getColumn(columnIdx);
-            Column sourceColumn = sourceTable.findColumn(targetColumn.getName(), _caseSensitive);
+            Column sourceColumn = intermediateTable.findColumn(targetColumn.getName(), _caseSensitive);
 
-            if (sourceColumn == null)
+            if (sourceColumn != null)
             {
-                if (_log.isInfoEnabled())
+                targetOrder.add(sourceColumn);
+            }
+        }
+
+        HashMap newPositions = new HashMap();
+
+        for (int columnIdx = 0; columnIdx < intermediateTable.getColumnCount(); columnIdx++)
+        {
+            Column sourceColumn = intermediateTable.getColumn(columnIdx);
+            int    targetIdx    = targetOrder.indexOf(sourceColumn);
+
+            if ((targetIdx >= 0) && (targetIdx != columnIdx))
+            {
+                newPositions.put(sourceColumn.getName(), new Integer(targetIdx));
+                if (sourceColumn.isPrimaryKey())
                 {
-                    _log.info("Column " + targetColumn.getName() + " needs to be created for table " + sourceTable.getName());
+                    numChangedPKs++;
                 }
+            }
+        }
 
-                AddColumnChange change = new AddColumnChange(sourceTable,
-                                                             targetColumn,
-                                                             columnIdx > 0 ? targetTable.getColumn(columnIdx - 1) : null,
-                                                             columnIdx < targetTable.getColumnCount() - 1 ? targetTable.getColumn(columnIdx + 1) : null);
+        if (!newPositions.isEmpty())
+        {
+            ColumnOrderChange change = new ColumnOrderChange(intermediateTable.getName(), newPositions);
 
-                changes.add(change);
-                addColumnChanges.put(targetColumn, change);
+            change.apply(intermediateModel, _caseSensitive);
+            if (numChangedPKs > 1)
+            {
+                // create pk change that only covers the order change
+                // fortunately, the order change will have adjusted the pk order already
+                changes.add(new PrimaryKeyChange(intermediateTable.getName(),
+                                                 getIntermediateColumnNamesFor(intermediateTable.getPrimaryKeyColumns(), intermediateTable)));
             }
-            else
+            changes.add(change);
+        }
+        return changes;
+    }
+
+    /**
+     * Creates change objects for columns that are present in the given source table but are no longer in the target
+     * table, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForRemovedColumns(Database sourceModel,
+                                          Table    sourceTable,
+                                          Database intermediateModel,
+                                          Table    intermediateTable,
+                                          Database targetModel,
+                                          Table    targetTable)
+    {
+        // if the platform does not support dropping pk columns, then the pk handling above will
+        // generate appropriate pk changes
+
+        List     changes = new ArrayList();
+        Column[] columns = intermediateTable.getColumns();
+
+        for (int columnIdx = 0; columnIdx < columns.length; columnIdx++)
+        {
+            Column sourceColumn = columns[columnIdx];
+            Column targetColumn = targetTable.findColumn(sourceColumn.getName(), _caseSensitive);
+
+            if (targetColumn == null)
             {
-                changes.addAll(compareColumns(sourceTable, sourceColumn, targetTable, targetColumn));
+                if (_log.isInfoEnabled())
+                {
+                    _log.info("Column " + sourceColumn.getName() + " needs to be removed from table " + intermediateTable.getName());
+                }
+
+                RemoveColumnChange change = new RemoveColumnChange(intermediateTable.getName(), sourceColumn.getName());
+
+                changes.add(change);
+                change.apply(intermediateModel, _caseSensitive);
             }
         }
-        // if the last columns in the target table are added, then we note this at the changes
-        for (int columnIdx = targetTable.getColumnCount() - 1; columnIdx >= 0; columnIdx--)
+        return changes;
+    }
+
+    /**
+     * Creates change objects for columns that are not present in the given source table but are in the target
+     * table, and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForAddedColumns(Database sourceModel,
+                                        Table    sourceTable,
+                                        Database intermediateModel,
+                                        Table    intermediateTable,
+                                        Database targetModel,
+                                        Table    targetTable)
+    {
+        List changes = new ArrayList();
+
+        for (int columnIdx = 0; columnIdx < targetTable.getColumnCount(); columnIdx++)
         {
-            Column          targetColumn = targetTable.getColumn(columnIdx);
-            AddColumnChange change       = (AddColumnChange)addColumnChanges.get(targetColumn);
+            Column targetColumn = targetTable.getColumn(columnIdx);
+            Column sourceColumn = intermediateTable.findColumn(targetColumn.getName(), _caseSensitive);
 
-            if (change == null)
+            if (sourceColumn == null)
             {
-                // column was not added, so we can ignore any columns before it that were added
-                break;
+                String          prevColumn   = (columnIdx > 0 ? intermediateTable.getColumn(columnIdx - 1).getName() : null);
+                String          nextColumn   = (columnIdx < intermediateTable.getColumnCount()  ? intermediateTable.getColumn(columnIdx).getName() : null);
+                Column          clonedColumn = _cloneHelper.clone(targetColumn, false);
+                AddColumnChange change       = new AddColumnChange(intermediateTable.getName(), clonedColumn, prevColumn, nextColumn);
+
+                changes.add(change);
+                change.apply(intermediateModel, _caseSensitive);
             }
-            else
+        }
+        return changes;
+    }
+
+    /**
+     * Creates change objects for columns that have a different in the given source and target table, and applies them
+     * to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForChangedColumns(Database sourceModel,
+                                          Table    sourceTable,
+                                          Database intermediateModel,
+                                          Table    intermediateTable,
+                                          Database targetModel,
+                                          Table    targetTable)
+    {
+        List changes = new ArrayList();
+
+        for (int columnIdx = 0; columnIdx < targetTable.getColumnCount(); columnIdx++)
+        {
+            Column targetColumn = targetTable.getColumn(columnIdx);
+            Column sourceColumn = intermediateTable.findColumn(targetColumn.getName(), _caseSensitive);
+
+            if (sourceColumn != null)
             {
-                change.setAtEnd(true);
+                ColumnDefinitionChange change = compareColumns(intermediateTable, sourceColumn, targetTable, targetColumn);
+
+                if (change != null)
+                {
+                    changes.add(change);
+                    change.apply(intermediateModel, _caseSensitive);
+                }
             }
         }
+        return changes;
+    }
 
+    /**
+     * Creates change objects for primary key differences (primary key added/removed/changed), and applies them to the given intermediate model.
+     * 
+     * @param sourceModel       The source model
+     * @param sourceTable       The source table
+     * @param intermediateModel The intermediate model to apply the changes to
+     * @param intermediateTable The table from the intermediate model corresponding to the source table
+     * @param targetModel       The target model
+     * @param targetTable       The target table
+     * @return The changes
+     */
+    protected List checkForPrimaryKeyChanges(Database sourceModel,
+                                             Table    sourceTable,
+                                             Database intermediateModel,
+                                             Table    intermediateTable,
+                                             Database targetModel,
+                                             Table    targetTable)
+    {
+        List     changes  = new ArrayList();
         Column[] sourcePK = sourceTable.getPrimaryKeyColumns();
+        Column[] curPK    = intermediateTable.getPrimaryKeyColumns();
         Column[] targetPK = targetTable.getPrimaryKeyColumns();
 
-        if ((sourcePK.length == 0) && (targetPK.length > 0))
+        if ((curPK.length == 0) && (targetPK.length > 0))
         {
             if (_log.isInfoEnabled())
             {
-                _log.info("A primary key needs to be added to the table " + sourceTable.getName());
+                _log.info("A primary key needs to be added to the table " + intermediateTable.getName());
             }
-            // we have to use the target table here because the primary key might
-            // reference a new column
-            changes.add(new AddPrimaryKeyChange(targetTable, targetPK));
+
+            AddPrimaryKeyChange change = new AddPrimaryKeyChange(intermediateTable.getName(), getIntermediateColumnNamesFor(targetPK, intermediateTable));
+
+            changes.add(change);
+            change.apply(intermediateModel, _caseSensitive);
         }
-        else if ((targetPK.length == 0) && (sourcePK.length > 0))
+        else if ((targetPK.length == 0) && (curPK.length > 0))
         {
             if (_log.isInfoEnabled())
             {
-                _log.info("The primary key needs to be removed from the table " + sourceTable.getName());
+                _log.info("The primary key needs to be removed from the table " + intermediateTable.getName());
             }
-            changes.add(new RemovePrimaryKeyChange(sourceTable, sourcePK));
+
+            RemovePrimaryKeyChange change = new RemovePrimaryKeyChange(intermediateTable.getName());
+
+            changes.add(change);
+            change.apply(intermediateModel, _caseSensitive);
         }
-        else if ((sourcePK.length > 0) && (targetPK.length > 0))
+        else
         {
             boolean changePK = false;
 
-            if (sourcePK.length != targetPK.length)
+            if ((curPK.length != targetPK.length) || (!_canDropPrimaryKeyColumns && sourcePK.length > targetPK.length))
             {
                 changePK = true;
             }
-            else
+            else if ((curPK.length > 0) && (targetPK.length > 0))
             {
-                for (int pkColumnIdx = 0; (pkColumnIdx < sourcePK.length) && !changePK; pkColumnIdx++)
+                for (int pkColumnIdx = 0; (pkColumnIdx < curPK.length) && !changePK; pkColumnIdx++)
                 {
-                    if ((_caseSensitive  && !sourcePK[pkColumnIdx].getName().equals(targetPK[pkColumnIdx].getName())) ||
-                        (!_caseSensitive && !sourcePK[pkColumnIdx].getName().equalsIgnoreCase(targetPK[pkColumnIdx].getName())))
+                    if (!StringUtils.equals(curPK[pkColumnIdx].getName(), targetPK[pkColumnIdx].getName(), _caseSensitive))
                     {
                         changePK = true;
                     }
@@ -295,101 +798,66 @@
             {
                 if (_log.isInfoEnabled())
                 {
-                    _log.info("The primary key of table " + sourceTable.getName() + " needs to be changed");
-                }
-                changes.add(new PrimaryKeyChange(sourceTable, targetPK));
-            }
-        }
-        
-        HashMap columnPosChanges = new HashMap();
-
-        for (int columnIdx = 0; columnIdx < sourceTable.getColumnCount(); columnIdx++)
-        {
-            Column sourceColumn = sourceTable.getColumn(columnIdx);
-            Column targetColumn = targetTable.findColumn(sourceColumn.getName(), _caseSensitive);
-
-            if (targetColumn == null)
-            {
-                if (_log.isInfoEnabled())
-                {
-                    _log.info("Column " + sourceColumn.getName() + " needs to be removed from table " + sourceTable.getName());
+                    _log.info("The primary key of table " + intermediateTable.getName() + " needs to be changed");
                 }
-                changes.add(new RemoveColumnChange(sourceTable, sourceColumn));
-            }
-            else
-            {
-                int targetColumnIdx = targetTable.getColumnIndex(targetColumn);
-
-                if (targetColumnIdx != columnIdx)
+                if (_generatePrimaryKeyChanges)
                 {
-                    columnPosChanges.put(sourceColumn, new Integer(targetColumnIdx));
+                    PrimaryKeyChange change = new PrimaryKeyChange(intermediateTable.getName(),
+                                                                   getIntermediateColumnNamesFor(targetPK, intermediateTable));
+    
+                    changes.add(change);
+                    change.apply(intermediateModel, changePK);
+                }
+                else
+                {
+                    RemovePrimaryKeyChange removePKChange = new RemovePrimaryKeyChange(intermediateTable.getName());
+                    AddPrimaryKeyChange    addPKChange    = new AddPrimaryKeyChange(intermediateTable.getName(),
+                                                                                    getIntermediateColumnNamesFor(targetPK, intermediateTable));
+
+                    changes.add(removePKChange);
+                    changes.add(addPKChange);
+                    removePKChange.apply(intermediateModel, _caseSensitive);
+                    addPKChange.apply(intermediateModel, _caseSensitive);
                 }
             }
         }
-        if (!columnPosChanges.isEmpty())
-        {
-            changes.add(new ColumnOrderChange(sourceTable, columnPosChanges));
-        }
-
         return changes;
     }
 
     /**
-     * Compares the two columns and returns the changes necessary to create the second
-     * column from the first one.
+     * Compares the two columns and returns the change necessary to create the second
+     * column from the first one if they differe.
      *  
      * @param sourceTable  The source table which contains the source column
      * @param sourceColumn The source column
      * @param targetTable  The target table which contains the target column
      * @param targetColumn The target column
-     * @return The changes
+     * @return The change or <code>null</code> if the columns are the same
      */
-    public List compareColumns(Table  sourceTable,
-                               Column sourceColumn,
-                               Table  targetTable,
-                               Column targetColumn)
+    protected ColumnDefinitionChange compareColumns(Table  sourceTable,
+                                                    Column sourceColumn,
+                                                    Table  targetTable,
+                                                    Column targetColumn)
     {
-        ArrayList changes = new ArrayList();
-
-        if (_platformInfo.getTargetJdbcType(targetColumn.getTypeCode()) != sourceColumn.getTypeCode())
-        {
-            changes.add(new ColumnDataTypeChange(sourceTable, sourceColumn, targetColumn.getTypeCode()));
-        }
-
-        boolean sizeMatters  = _platformInfo.hasSize(sourceColumn.getTypeCode());
-        boolean scaleMatters = _platformInfo.hasPrecisionAndScale(sourceColumn.getTypeCode());
-
-        if (sizeMatters &&
-            !StringUtils.equals(sourceColumn.getSize(), targetColumn.getSize()))
-        {
-            changes.add(new ColumnSizeChange(sourceTable, sourceColumn, targetColumn.getSizeAsInt(), targetColumn.getScale()));
-        }
-        else if (scaleMatters &&
-            (!StringUtils.equals(sourceColumn.getSize(), targetColumn.getSize()) ||
-             (sourceColumn.getScale() != targetColumn.getScale())))
+        if (ColumnDefinitionChange.isChanged(getPlatformInfo(), sourceColumn, targetColumn))
         {
-            changes.add(new ColumnSizeChange(sourceTable, sourceColumn, targetColumn.getSizeAsInt(), targetColumn.getScale()));
+            Column  newColumnDef   = _cloneHelper.clone(sourceColumn, true);
+            int     targetTypeCode = _platformInfo.getTargetJdbcType(targetColumn.getTypeCode());
+            boolean sizeMatters    = _platformInfo.hasSize(targetTypeCode);
+            boolean scaleMatters   = _platformInfo.hasPrecisionAndScale(targetTypeCode);
+
+            newColumnDef.setTypeCode(targetColumn.getTypeCode());
+            newColumnDef.setSize(sizeMatters || scaleMatters ? targetColumn.getSize() : null);
+            newColumnDef.setAutoIncrement(targetColumn.isAutoIncrement());
+            newColumnDef.setRequired(targetColumn.isRequired());
+            newColumnDef.setDescription(targetColumn.getDescription());
+            newColumnDef.setDefaultValue(targetColumn.getDefaultValue());
+            return new ColumnDefinitionChange(sourceTable.getName(), sourceColumn.getName(), newColumnDef);
         }
-
-        Object sourceDefaultValue = sourceColumn.getParsedDefaultValue();
-        Object targetDefaultValue = targetColumn.getParsedDefaultValue();
-
-        if (((sourceDefaultValue == null) && (targetDefaultValue != null)) ||
-            ((sourceDefaultValue != null) && !sourceDefaultValue.equals(targetDefaultValue)))
-        {
-            changes.add(new ColumnDefaultValueChange(sourceTable, sourceColumn, targetColumn.getDefaultValue()));
-        }
-
-        if (sourceColumn.isRequired() != targetColumn.isRequired())
+        else
         {
-            changes.add(new ColumnRequiredChange(sourceTable, sourceColumn));
+            return null;
         }
-        if (sourceColumn.isAutoIncrement() != targetColumn.isAutoIncrement())
-        {
-            changes.add(new ColumnAutoIncrementChange(sourceTable, sourceColumn));
-        }
-
-        return changes;
     }
 
     /**
@@ -403,7 +871,7 @@
      * @param fk    The original foreign key
      * @return The corresponding foreign key if found
      */
-    private ForeignKey findCorrespondingForeignKey(Table table, ForeignKey fk)
+    protected ForeignKey findCorrespondingForeignKey(Table table, ForeignKey fk)
     {
         for (int fkIdx = 0; fkIdx < table.getForeignKeyCount(); fkIdx++)
         {
@@ -428,7 +896,7 @@
      * @param index The original index
      * @return The corresponding index if found
      */
-    private Index findCorrespondingIndex(Table table, Index index)
+    protected Index findCorrespondingIndex(Table table, Index index)
     {
         for (int indexIdx = 0; indexIdx < table.getIndexCount(); indexIdx++)
         {

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/Pair.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/Pair.java?rev=602807&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/Pair.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/Pair.java Mon Dec 10 00:20:47 2007
@@ -0,0 +1,65 @@
+package org.apache.ddlutils.alteration;
+
+/*
+ * 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.
+ */
+
+/**
+ * Represents a pair of objects.
+ * 
+ * @version $Revision: $
+ */
+public class Pair
+{
+    /** The first object. */
+    private final Object _firstObj;
+    /** The first object. */
+    private final Object _secondObj;
+
+    /**
+     * Creates a pair object.
+     * 
+     * @param firstObj  The first object
+     * @param secondObj The second object
+     */
+    public Pair(Object firstObj, Object secondObj)
+    {
+        _firstObj  = firstObj;
+        _secondObj = secondObj;
+    }
+
+    /**
+     * Returns the first object of the pair.
+     * 
+     * @return The first object
+     */
+    public Object getFirst()
+    {
+        return _firstObj;
+    }
+
+    /**
+     * Returns the second object of the pair.
+     * 
+     * @return The second object
+     */
+    public Object getSecond()
+    {
+        return _secondObj;
+    }
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/PrimaryKeyChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/PrimaryKeyChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/PrimaryKeyChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/PrimaryKeyChange.java Mon Dec 10 00:20:47 2007
@@ -30,40 +30,27 @@
  */
 public class PrimaryKeyChange extends TableChangeImplBase
 {
-    /** The columns making up the original primary key. */
-    private Column[] _oldPrimaryKeyColumns;
-    /** The columns making up the new primary key. */
-    private Column[] _newPrimaryKeyColumns;
+    /** The names of the columns making up the new primary key. */
+    private String[] _newPrimaryKeyColumns;
 
     /**
      * Creates a new change object.
      * 
-     * @param table                The table whose primary key is to be changed
-     * @param newPrimaryKeyColumns The columns making up the new primary key
+     * @param tableName            The name of the table whose primary key is to be changed
+     * @param newPrimaryKeyColumns The names of the columns making up the new primary key
      */
-    public PrimaryKeyChange(Table table, Column[] newPrimaryKeyColumns)
+    public PrimaryKeyChange(String tableName, String[] newPrimaryKeyColumns)
     {
-        super(table);
-        _oldPrimaryKeyColumns = table.getPrimaryKeyColumns();
+        super(tableName);
         _newPrimaryKeyColumns = newPrimaryKeyColumns;
     }
 
     /**
-     * Returns the columns making up the original primary key.
+     * Returns the names of the columns making up the new primary key.
      *
-     * @return The columns
+     * @return The column names
      */
-    public Column[] getOldPrimaryKeyColumns()
-    {
-        return _oldPrimaryKeyColumns;
-    }
-
-    /**
-     * Returns the columns making up the new primary key.
-     *
-     * @return The columns
-     */
-    public Column[] getNewPrimaryKeyColumns()
+    public String[] getNewPrimaryKeyColumns()
     {
         return _newPrimaryKeyColumns;
     }
@@ -73,17 +60,16 @@
      */
     public void apply(Database model, boolean caseSensitive)
     {
-        Table table = findChangedTable(model, caseSensitive);
+        Table    table  = findChangedTable(model, caseSensitive);
+        Column[] pkCols = table.getPrimaryKeyColumns();
 
-        for (int idx = 0; idx < _oldPrimaryKeyColumns.length; idx++)
+        for (int idx = 0; idx < pkCols.length; idx++)
         {
-            Column column = table.findColumn(_oldPrimaryKeyColumns[idx].getName(), caseSensitive);
-
-            column.setPrimaryKey(false);
+            pkCols[idx].setPrimaryKey(false);
         }
         for (int idx = 0; idx < _newPrimaryKeyColumns.length; idx++)
         {
-            Column column = table.findColumn(_newPrimaryKeyColumns[idx].getName(), caseSensitive);
+            Column column = table.findColumn(_newPrimaryKeyColumns[idx], caseSensitive);
 
             column.setPrimaryKey(true);
         }

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RecreateTableChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RecreateTableChange.java?rev=602807&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RecreateTableChange.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RecreateTableChange.java Mon Dec 10 00:20:47 2007
@@ -0,0 +1,103 @@
+package org.apache.ddlutils.alteration;
+
+/*
+ * 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.List;
+
+import org.apache.ddlutils.model.CloneHelper;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+
+/**
+ * Represents the recreation of a table, i.e. creating a temporary table using the target table definition,
+ * copying the data from the original table into this temporary table, dropping the original table and
+ * finally renaming the temporary table to the final table. This change is only created by the model
+ * comparator if the table definition change predicate flags a table change as unsupported.
+ *  
+ * @version $Revision: $
+ */
+public class RecreateTableChange extends TableChangeImplBase
+{
+    /** The target table definition. */
+    private Table _targetTable;
+    /** The original table changes, one of which is unsupported by the current platform. */
+    private List  _originalChanges;
+
+    /**
+     * Creates a new change object for recreating a table. This change is used to specify that a table needs
+     * to be dropped and then re-created (with changes). In the standard model comparison algorithm, it will
+     * replace all direct changes to the table's columns (i.e. foreign key and index changes are unaffected).  
+     * 
+     * @param tableName       The name of the table
+     * @param targetTable     The table as it should be; note that the change object will keep a reference
+     *                        to this table which means that it should not be changed after creating this
+     *                        change object
+     * @param originalChanges The original changes that this change object replaces
+     */
+    public RecreateTableChange(String tableName, Table targetTable, List originalChanges)
+    {
+        super(tableName);
+        _targetTable     = targetTable;
+        _originalChanges = originalChanges;
+    }
+
+    /**
+     * Returns the original table changes, one of which is unsupported by the current platform.
+     * 
+     * @return The table changes
+     */
+    public List getOriginalChanges()
+    {
+        return _originalChanges;
+    }
+
+    /**
+     * Returns the target table definition. Due to when an object of this kind is created in the comparison
+     * process, this table object will not have any foreign keys pointing to or from it, i.e. it is
+     * independent of any model.
+     * 
+     * @return The table definition
+     */
+    public Table getTargetTable()
+    {
+        return _targetTable;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply(Database database, boolean caseSensitive)
+    {
+        // we only need to replace the table in the model, as there can't be a
+        // foreign key from or to it when these kind of changes are created
+        for (int tableIdx = 0; tableIdx < database.getTableCount(); tableIdx++)
+        {
+            Table curTable = database.getTable(tableIdx);
+
+            if ((caseSensitive  && curTable.getName().equals(getChangedTable())) ||
+                (!caseSensitive && curTable.getName().equalsIgnoreCase(getChangedTable())))
+            {
+                database.removeTable(tableIdx);
+                database.addTable(tableIdx, new CloneHelper().clone(_targetTable, true, false, database, caseSensitive));
+                break;
+            }
+        }
+    }
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveColumnChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveColumnChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveColumnChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveColumnChange.java Mon Dec 10 00:20:47 2007
@@ -19,9 +19,7 @@
  * under the License.
  */
 
-import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
-import org.apache.ddlutils.model.Table;
 
 /**
  * Represents the removal of a column from a table.
@@ -33,12 +31,12 @@
     /**
      * Creates a new change object.
      * 
-     * @param table  The table to remove the column from
-     * @param column The column
+     * @param tableName  The name of the table to remove the column from
+     * @param columnName The column's name
      */
-    public RemoveColumnChange(Table table, Column column)
+    public RemoveColumnChange(String tableName, String columnName)
     {
-        super(table, column);
+        super(tableName, columnName);
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveForeignKeyChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveForeignKeyChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveForeignKeyChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveForeignKeyChange.java Mon Dec 10 00:20:47 2007
@@ -21,7 +21,6 @@
 
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.ForeignKey;
-import org.apache.ddlutils.model.Table;
 
 /**
  * Represents the removal of a foreign key from a table. Note that for
@@ -35,12 +34,12 @@
     /**
      * Creates a new change object.
      * 
-     * @param table      The table to remove the foreign key from
+     * @param tableName  The name of the table to remove the foreign key from
      * @param foreignKey The foreign key
      */
-    public RemoveForeignKeyChange(Table table, ForeignKey foreignKey)
+    public RemoveForeignKeyChange(String tableName, ForeignKey foreignKey)
     {
-        super(table, foreignKey);
+        super(tableName, foreignKey);
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveIndexChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveIndexChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveIndexChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveIndexChange.java Mon Dec 10 00:20:47 2007
@@ -21,7 +21,6 @@
 
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.Index;
-import org.apache.ddlutils.model.Table;
 
 /**
  * Represents the removal of an index from a table.
@@ -33,12 +32,12 @@
     /**
      * Creates a new change object.
      * 
-     * @param table The table to remove the index from
-     * @param index The index
+     * @param tableName The name of the table to remove the index from
+     * @param index     The index
      */
-    public RemoveIndexChange(Table table, Index index)
+    public RemoveIndexChange(String tableName, Index index)
     {
-        super(table, index);
+        super(tableName, index);
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemovePrimaryKeyChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemovePrimaryKeyChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemovePrimaryKeyChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemovePrimaryKeyChange.java Mon Dec 10 00:20:47 2007
@@ -30,29 +30,14 @@
  */
 public class RemovePrimaryKeyChange extends TableChangeImplBase
 {
-    /** The columns making up the primary key. */
-    private Column[] _primaryKeyColumns;
-
     /**
      * Creates a new change object.
      * 
-     * @param table             The table to remove the primary key from
-     * @param primaryKeyColumns The columns making up the primary key
+     * @param tableName The name of he table to remove the primary key from
      */
-    public RemovePrimaryKeyChange(Table table, Column[] primaryKeyColumns)
+    public RemovePrimaryKeyChange(String tableName)
     {
-        super(table);
-        _primaryKeyColumns = primaryKeyColumns;
-    }
-
-    /**
-     * Returns the primary key columns making up the primary key.
-     *
-     * @return The primary key columns
-     */
-    public Column[] getPrimaryKeyColumns()
-    {
-        return _primaryKeyColumns;
+        super(tableName);
     }
 
     /**
@@ -60,13 +45,12 @@
      */
     public void apply(Database model, boolean caseSensitive)
     {
-        Table table = findChangedTable(model, caseSensitive);
+        Table    table  = findChangedTable(model, caseSensitive);
+        Column[] pkCols = table.getPrimaryKeyColumns();
 
-        for (int idx = 0; idx < _primaryKeyColumns.length; idx++)
+        for (int idx = 0; idx < pkCols.length; idx++)
         {
-            Column column = table.findColumn(_primaryKeyColumns[idx].getName(), caseSensitive);
-
-            column.setPrimaryKey(false);
+            pkCols[idx].setPrimaryKey(false);
         }
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveTableChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveTableChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveTableChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/RemoveTableChange.java Mon Dec 10 00:20:47 2007
@@ -25,6 +25,7 @@
 /**
  * Represents the removal of a table from a model.
  * 
+ * TODO: this should be a model change
  * @version $Revision: $
  */
 public class RemoveTableChange extends TableChangeImplBase
@@ -32,11 +33,11 @@
     /**
      * Creates a new change object.
      * 
-     * @param table The table
+     * @param tableName The name of the table to be removed
      */
-    public RemoveTableChange(Table table)
+    public RemoveTableChange(String tableName)
     {
-        super(table);
+        super(tableName);
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChange.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChange.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChange.java Mon Dec 10 00:20:47 2007
@@ -30,11 +30,11 @@
 public interface TableChange extends ModelChange
 {
     /**
-     * Returns the affected table from the original model.
+     * Returns the name of the affected table from the original model.
      * 
-     * @return The affected table
+     * @return The name of the affected table
      */
-    public Table getChangedTable();
+    public String getChangedTable();
 
     /**
      * Finds the table object corresponding to the changed table in the given database model.

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChangeImplBase.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChangeImplBase.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChangeImplBase.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableChangeImplBase.java Mon Dec 10 00:20:47 2007
@@ -29,25 +29,25 @@
  */
 public abstract class TableChangeImplBase implements TableChange
 {
-    /** The affected table. */
-    private Table _table;
+    /** The name of the affected table. */
+    private String _tableName;
 
     /**
      * Creates a new change object.
      * 
-     * @param table The table
+     * @param tableName The table's name
      */
-    public TableChangeImplBase(Table table)
+    public TableChangeImplBase(String tableName)
     {
-        _table = table;
+        _tableName = tableName;
     }
 
     /**
      * {@inheritDoc}
      */
-    public Table getChangedTable()
+    public String getChangedTable()
     {
-        return _table;
+        return _tableName;
     }
 
     /**
@@ -55,6 +55,6 @@
      */
     public Table findChangedTable(Database model, boolean caseSensitive)
     {
-    	return model.findTable(_table.getName(), caseSensitive);
+    	return model.findTable(_tableName, caseSensitive);
     }
 }

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableDefinitionChangesPredicate.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableDefinitionChangesPredicate.java?rev=602807&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableDefinitionChangesPredicate.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/TableDefinitionChangesPredicate.java Mon Dec 10 00:20:47 2007
@@ -0,0 +1,45 @@
+package org.apache.ddlutils.alteration;
+
+/*
+ * 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.List;
+
+import org.apache.ddlutils.model.Table;
+
+/**
+ * Defines a predicate that allows platforms to state whether all of the given table definition
+ * changes (i.e. column changes and primary key changes) are supported by the platform or not.
+ * 
+ * @version $Revision: $
+ */
+public interface TableDefinitionChangesPredicate
+{
+    /**
+     * Evaluates the given list of table changes and determines whether they are supported.
+     * 
+     * @param intermediateTable The current table object which has certain non-table-definition
+     *                          changes already applied (those that would come before the give
+     *                          list of changes in the result of
+     *                          {@link ModelComparator#compare(org.apache.ddlutils.model.Database, org.apache.ddlutils.model.Database)}
+     * @param changes The non-empty list of changes
+     * @return <code>true</code> if the current plaform supports them
+     */
+    public boolean areSupported(Table intermediateTable, List changes);
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java Mon Dec 10 00:20:47 2007
@@ -26,8 +26,8 @@
 import org.apache.commons.lang.enums.ValuedEnum;
 
 /**
- * Represents the different cascade actions for {@link ForeignKey#onDelete} and
- * {@link ForeignKey#onUdate}.
+ * Represents the different cascade actions for the <code>onDelete</code> and
+ * <code>onUpdate</code> properties of {@link ForeignKey}.
  * 
  * @version $Revision: $
  */

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CloneHelper.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CloneHelper.java?rev=602807&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CloneHelper.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CloneHelper.java Mon Dec 10 00:20:47 2007
@@ -0,0 +1,221 @@
+package org.apache.ddlutils.model;
+
+/*
+ * 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.
+ */
+
+/**
+ * Helper class that provides cloning of model elements.
+ * 
+ * @version $Revision: $
+ */
+public class CloneHelper
+{
+    /**
+     * Returns a deep clone of the given model object, including all tables, foreign keys, indexes etc.
+     *
+     * @param source The source model
+     * @return The clone
+     */
+    public Database clone(Database source)
+    {
+        Database result = new Database();
+
+        result.setName(source.getName());
+        result.setIdMethod(source.getIdMethod());
+        result.setVersion(source.getVersion());
+
+        for (int tableIdx = 0; tableIdx < source.getTableCount(); tableIdx++)
+        {
+            Table sourceTable = source.getTable(tableIdx);
+
+            result.addTable(clone(sourceTable, true, false, result, true));
+        }
+        for (int tableIdx = 0; tableIdx < source.getTableCount(); tableIdx++)
+        {
+            Table sourceTable = source.getTable(tableIdx);
+            Table clonedTable = result.getTable(tableIdx);
+
+            for (int fkIdx = 0; fkIdx < sourceTable.getForeignKeyCount(); fkIdx++)
+            {
+                ForeignKey sourceFk = sourceTable.getForeignKey(fkIdx);
+
+                clonedTable.addForeignKey(clone(sourceFk, clonedTable, result, true));
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns a clone of the given table.
+     * 
+     * @param source           The source table
+     * @param cloneIndexes     Whether to clone indexes; if <code>false</code> then the clone will
+     *                         not have any indexes
+     * @param cloneForeignKeys Whether to clone foreign kets; if <code>false</code> then the clone
+     *                         will not have any foreign keys
+     * @param targetModel      The target model, can be <code>null</code> if
+     *                         <code>cloneForeignKeys=false</code>
+     * @param caseSensitive    Whether comparison is case sensitive (for cloning foreign keys)
+     * @return The clone
+     */
+    public Table clone(Table source, boolean cloneIndexes, boolean cloneForeignKeys, Database targetModel, boolean caseSensitive)
+    {
+        Table result = new Table();
+
+        result.setCatalog(source.getCatalog());
+        result.setSchema(source.getSchema());
+        result.setName(source.getName());
+        result.setType(source.getType());
+
+        for (int colIdx = 0; colIdx < source.getColumnCount(); colIdx++)
+        {
+            result.addColumn(clone(source.getColumn(colIdx), true));
+        }
+        if (cloneIndexes)
+        {
+            for (int indexIdx = 0; indexIdx < source.getIndexCount(); indexIdx++)
+            {
+                result.addIndex(clone(source.getIndex(indexIdx), result, true));
+            }
+        }
+        if (cloneForeignKeys)
+        {
+            for (int fkIdx = 0; fkIdx < source.getForeignKeyCount(); fkIdx++)
+            {
+                result.addForeignKey(clone(source.getForeignKey(fkIdx), result, targetModel, caseSensitive));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a clone of the given source column.
+     * 
+     * @param source                The source column
+     * @param clonePrimaryKeyStatus Whether to clone the column's primary key status; if <code>false</code>
+     *                              then the clone will not be a primary key column
+     * @return The clone
+     */
+    public Column clone(Column source, boolean clonePrimaryKeyStatus)
+    {
+        Column result = new Column();
+
+        result.setName(source.getName());
+        result.setJavaName(source.getJavaName());
+        result.setPrimaryKey(clonePrimaryKeyStatus ? source.isPrimaryKey() : false);
+        result.setRequired(source.isRequired());
+        result.setAutoIncrement(source.isAutoIncrement());
+        result.setTypeCode(source.getTypeCode());
+        result.setSize(source.getSize());
+        result.setDefaultValue(source.getDefaultValue());
+
+        return result;
+    }
+
+    /**
+     * Returns a clone of the given source index.
+     * 
+     * @param source        The source index
+     * @param targetTable   The table whose columns shall be used by the clone
+     * @param caseSensitive Whether comparison is case sensitive (for finding the columns
+     *                      in the target table)
+     * @return The clone
+     */
+    public Index clone(Index source, Table targetTable, boolean caseSensitive)
+    {
+        Index result = (source.isUnique() ? (Index)new UniqueIndex() : (Index)new NonUniqueIndex());
+
+        result.setName(source.getName());
+        for (int colIdx = 0; colIdx < source.getColumnCount(); colIdx++)
+        {
+            IndexColumn column = source.getColumn(colIdx);
+
+            result.addColumn(clone(column, targetTable, caseSensitive));
+        }
+        return result;
+    }
+
+    /**
+     * Returns a clone of the given index column.
+     * 
+     * @param source        The source index column
+     * @param targetTable   The table containing the column to be used by the clone
+     * @param caseSensitive Whether comparison is case sensitive (for finding the columns
+     *                      in the target table)
+     * @return The clone
+     */
+    public IndexColumn clone(IndexColumn source, Table targetTable, boolean caseSensitive)
+    {
+        IndexColumn result = new IndexColumn();
+
+        result.setColumn(targetTable.findColumn(source.getName(), caseSensitive));
+        result.setOrdinalPosition(source.getOrdinalPosition());
+        result.setSize(source.getSize());
+        return result;
+    }
+
+    /**
+     * Returns a clone of the given source foreign key.
+     * 
+     * @param source        The source foreign key
+     * @param owningTable   The table owning the source foreign key
+     * @param targetModel   The target model containing the tables that the clone shall link
+     * @param caseSensitive Whether comparison is case sensitive (for finding the columns
+     *                      in the target model)
+     * @return The clone
+     */
+    public ForeignKey clone(ForeignKey source, Table owningTable, Database targetModel, boolean caseSensitive)
+    {
+        ForeignKey result       = new ForeignKey();
+        Table      foreignTable = targetModel.findTable(source.getForeignTableName(), caseSensitive);
+        
+        result.setName(source.getName());
+        result.setForeignTable(foreignTable);
+        result.setAutoIndexPresent(source.isAutoIndexPresent());
+
+        for (int refIdx = 0; refIdx < source.getReferenceCount(); refIdx++)
+        {
+            Reference ref = source.getReference(refIdx);
+
+            result.addReference(clone(ref, owningTable, foreignTable, caseSensitive));
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a clone of the given source reference.
+     * 
+     * @param source        The source reference
+     * @param localTable    The table containing the local column to be used by the reference
+     * @param foreignTable  The table containing the foreign column to be used by the reference
+     * @param caseSensitive Whether comparison is case sensitive (for finding the columns
+     *                      in the tables)
+     * @return The clone
+     */
+    public Reference clone(Reference source, Table localTable, Table foreignTable, boolean caseSensitive)
+    {
+        Reference result = new Reference();
+
+        result.setLocalColumn(localTable.findColumn(source.getLocalColumnName(), caseSensitive));
+        result.setForeignColumn(foreignTable.findColumn(source.getForeignColumnName(), caseSensitive));
+        return result;
+    }
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Column.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Column.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Column.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Column.java Mon Dec 10 00:20:47 2007
@@ -36,7 +36,7 @@
  * 
  * @version $Revision$
  */
-public class Column implements Cloneable, Serializable
+public class Column implements Serializable
 {
     /** Unique ID for serialization purposes. */
     private static final long serialVersionUID = -6226348998874210093L;
@@ -478,29 +478,6 @@
     public void setDefaultValue(String defaultValue)
     {
         _defaultValue = defaultValue;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Object clone() throws CloneNotSupportedException
-    {
-        Column result = (Column)super.clone();
-
-        result._name            = _name;
-        result._javaName        = _javaName;
-        result._primaryKey      = _primaryKey;
-        result._required        = _required;
-        result._autoIncrement   = _autoIncrement;
-        result._typeCode        = _typeCode;
-        result._type            = _type;
-        result._size            = _size;
-        result._defaultValue    = _defaultValue;
-        result._scale           = _scale;
-        result._size            = _size;
-        result._sizeAsInt       = _sizeAsInt;
-
-        return result;
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java?rev=602807&r1=602806&r2=602807&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java Mon Dec 10 00:20:47 2007
@@ -40,7 +40,7 @@
  *
  * @version $Revision$
  */
-public class Database implements Serializable, Cloneable
+public class Database implements Serializable
 {
     /** Unique ID for serialization purposes. */
     private static final long serialVersionUID = -3160443396757573868L;
@@ -64,22 +64,32 @@
      */
     public void mergeWith(Database otherDb) throws ModelException
     {
-        for (Iterator it = otherDb._tables.iterator(); it.hasNext();)
+        CloneHelper cloneHelper = new CloneHelper();
+
+        for (int tableIdx = 0; tableIdx < otherDb.getTableCount(); tableIdx++)
         {
-            Table table = (Table)it.next();
+            Table table = otherDb.getTable(tableIdx);
 
             if (findTable(table.getName()) != null)
             {
                 // TODO: It might make more sense to log a warning and overwrite the table (or merge them) ?
                 throw new ModelException("Cannot merge the models because table "+table.getName()+" already defined in this model");
             }
-            try
+            else
             {
-                addTable((Table)table.clone());
+                addTable(cloneHelper.clone(table, true, false, this, true));
             }
-            catch (CloneNotSupportedException ex)
+        }
+        for (int tableIdx = 0; tableIdx < otherDb.getTableCount(); tableIdx++)
+        {
+            Table otherTable = otherDb.getTable(tableIdx);
+            Table localTable = findTable(otherTable.getName());
+
+            for (int fkIdx = 0; fkIdx < otherTable.getForeignKeyCount(); fkIdx++)
             {
-                // won't happen
+                ForeignKey fk = otherTable.getForeignKey(fkIdx);
+
+                localTable.addForeignKey(cloneHelper.clone(fk, localTable, this, false));
             }
         }
     }
@@ -292,7 +302,7 @@
                 }
                 if (namesOfProcessedColumns.contains(column.getName()))
                 {
-                    throw new ModelException("There are multiple column with the name "+column.getName()+" in the table "+curTable.getName());
+                    throw new ModelException("There are multiple columns with the name "+column.getName()+" in the table "+curTable.getName());
                 }
                 namesOfProcessedColumns.add(column.getName());
 
@@ -526,21 +536,6 @@
     public DynaBean createDynaBeanFor(String tableName, boolean caseSensitive) throws SqlDynaException
     {
         return getDynaClassCache().createNewInstance(findTable(tableName, caseSensitive));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Object clone() throws CloneNotSupportedException
-    {
-        Database result = (Database)super.clone();
-
-        result._name     = _name;
-        result._idMethod = _idMethod;
-        result._version  = _version;
-        result._tables   = (ArrayList)_tables.clone();
-
-        return result;
     }
 
     /**