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 2006/05/09 00:20:40 UTC

svn commit: r405198 - in /db/ddlutils/trunk/src: java/org/apache/ddlutils/alteration/ java/org/apache/ddlutils/model/ java/org/apache/ddlutils/platform/hsqldb/ java/org/apache/ddlutils/platform/postgresql/ test/org/apache/ddlutils/io/

Author: tomdz
Date: Mon May  8 15:20:37 2006
New Revision: 405198

URL: http://svn.apache.org/viewcvs?rev=405198&view=rev
Log:
Enhanced alteration for Derby, PostgreSQL, HsqlDb
Added more alteration tests

Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/AddColumnChange.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/postgresql/PostgreSqlBuilder.java
    db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestAlteration.java

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/AddColumnChange.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/AddColumnChange.java?rev=405198&r1=405197&r2=405198&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/AddColumnChange.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/AddColumnChange.java Mon May  8 15:20:37 2006
@@ -30,17 +30,31 @@
 {
     /** The new column. */
     private Column _newColumn;
+    /** The column before which the new column should be added. */
+    private Column _nextColumn;
 
     /**
      * Creates a new change object.
      * 
-     * @param table     The table to add the column to
-     * @param newColumn The new column
+     * @param table      The table to add the column to
+     * @param nextColumn The column before which the new column should be added
+     * @param newColumn  The new column
      */
-    public AddColumnChange(Table table, Column newColumn)
+    public AddColumnChange(Table table, Column nextColumn, Column newColumn)
     {
         super(table);
-        _newColumn = newColumn;
+        _nextColumn = nextColumn;
+        _newColumn  = newColumn;
+    }
+
+    /**
+     * Returns the column before which the new column should be added.
+     *
+     * @return The next column
+     */
+    public Column getNextColumn()
+    {
+        return _nextColumn;
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/alteration/ModelComparator.java?rev=405198&r1=405197&r2=405198&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 May  8 15:20:37 2006
@@ -212,7 +212,9 @@
                 {
                     _log.info("Column " + targetColumn.getName() + " needs to be created for table " + sourceTable.getName());
                 }
-                changes.add(new AddColumnChange(sourceTable, targetColumn));
+                changes.add(new AddColumnChange(sourceTable,
+                                                columnIdx < targetTable.getColumnCount() - 1 ? targetTable.getColumn(columnIdx + 1) :null,
+                                                targetColumn));
             }
             else
             {

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java?rev=405198&r1=405197&r2=405198&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java Mon May  8 15:20:37 2006
@@ -200,7 +200,7 @@
     }
 
     /**
-     * Adds the given column at the specified position .
+     * Adds the given column at the specified position.
      * 
      * @param idx    The index where to add the column
      * @param column The column
@@ -210,6 +210,28 @@
         if (column != null)
         {
             _columns.add(idx, column);
+        }
+    }
+
+    /**
+     * Adds the column after the given previous column.
+     * 
+     * @param previousColumn The column to add the new column after; use
+     *                       <code>null</code> for adding at the begin
+     * @param column         The column
+     */
+    public void addColumn(Column previousColumn, Column column)
+    {
+        if (column != null)
+        {
+            if (previousColumn == null)
+            {
+                _columns.add(0, column);
+            }
+            else
+            {
+                _columns.add(_columns.indexOf(previousColumn), column);
+            }
         }
     }
 

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/hsqldb/HsqlDbBuilder.java?rev=405198&r1=405197&r2=405198&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 May  8 15:20:37 2006
@@ -17,8 +17,17 @@
  */
 
 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.Table;
 import org.apache.ddlutils.platform.SqlBuilder;
 
@@ -59,5 +68,103 @@
     public String getSelectLastInsertId(Table table) 
     {
         return "CALL IDENTITY()";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void processTableStructureChanges(Database currentModel,
+                                                Database desiredModel,
+                                                Table    sourceTable,
+                                                Table    targetTable,
+                                                Map      parameters,
+                                                List     changes) throws IOException
+    {
+        // 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);
+            addColumnChange.apply(currentModel);
+            changeIt.remove();
+        }
+
+        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
+        {
+            TableChange change = (TableChange)changeIt.next();
+
+            if (change instanceof RemoveColumnChange) 
+            {
+                RemoveColumnChange removeColumnChange = (RemoveColumnChange)change;
+
+                // HsqlDb can only drop columns that are not part of a primary key
+                if (!removeColumnChange.getColumn().isPrimaryKey())
+                {
+                    processChange(currentModel, desiredModel, removeColumnChange);
+                    change.apply(currentModel);
+                    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
+    {
+        print("ALTER TABLE ");
+        printlnIdentifier(getTableName(change.getChangedTable()));
+        printIndent();
+        print("ADD COLUMN ");
+        writeColumn(change.getChangedTable(), change.getNewColumn());
+        if (change.getNextColumn() != null)
+        {
+            print(" BEFORE ");
+            printIdentifier(getColumnName(change.getNextColumn()));
+        }
+        printEndOfStatement();
+    }
+
+    /**
+     * Processes the removal of 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
+    {
+        print("ALTER TABLE ");
+        printlnIdentifier(getTableName(change.getChangedTable()));
+        printIndent();
+        print("DROP COLUMN ");
+        printIdentifier(getColumnName(change.getColumn()));
+        printEndOfStatement();
     }
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/postgresql/PostgreSqlBuilder.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/postgresql/PostgreSqlBuilder.java?rev=405198&r1=405197&r2=405198&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/postgresql/PostgreSqlBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/postgresql/PostgreSqlBuilder.java Mon May  8 15:20:37 2006
@@ -17,9 +17,14 @@
  */
 
 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.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;
@@ -153,5 +158,87 @@
             }
             return result.toString();
         }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void processTableStructureChanges(Database currentModel,
+                                                Database desiredModel,
+                                                Table    sourceTable,
+                                                Table    targetTable,
+                                                Map      parameters,
+                                                List     changes) throws IOException
+    {
+        for (Iterator changeIt = changes.iterator(); changeIt.hasNext();)
+        {
+            TableChange change = (TableChange)changeIt.next();
+
+            if (change instanceof AddColumnChange)
+            {
+                AddColumnChange addColumnChange = (AddColumnChange)change;
+
+                // We can only use PostgreSQL-specific SQL if
+                // * the column is not set to NOT NULL (the constraint would be applied immediately
+                //   which will not work if there is already data in the table)
+                // * the column has no default value (it would be applied after the change which
+                //   means that PostgreSQL would behave differently from other databases where the
+                //   default is applied to every column)
+                // * the column is added at the end of the table (PostgreSQL does not support
+                //   insertion of a column)
+                if (!addColumnChange.getNewColumn().isRequired() &&
+                    (addColumnChange.getNewColumn().getDefaultValue() == null) &&
+                    (addColumnChange.getNextColumn() == null))
+                {
+                    processChange(currentModel, desiredModel, addColumnChange);
+                    change.apply(currentModel);
+                    changeIt.remove();
+                }
+            }
+            else if (change instanceof RemoveColumnChange)
+            {
+                processChange(currentModel, desiredModel, (RemoveColumnChange)change);
+                change.apply(currentModel);
+                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
+    {
+        print("ALTER TABLE ");
+        printlnIdentifier(getTableName(change.getChangedTable()));
+        printIndent();
+        print("ADD COLUMN ");
+        writeColumn(change.getChangedTable(), change.getNewColumn());
+        printEndOfStatement();
+    }
+
+    /**
+     * Processes the removal of 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
+    {
+        print("ALTER TABLE ");
+        printlnIdentifier(getTableName(change.getChangedTable()));
+        printIndent();
+        print("DROP COLUMN ");
+        printIdentifier(getColumnName(change.getColumn()));
+        printEndOfStatement();
     }
 }

Modified: db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestAlteration.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestAlteration.java?rev=405198&r1=405197&r2=405198&view=diff
==============================================================================
--- db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestAlteration.java (original)
+++ db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestAlteration.java Mon May  8 15:20:37 2006
@@ -219,7 +219,7 @@
     }
 
     /**
-     * Tests the addition of a column default value.
+     * Tests the addition of a column's default value.
      */
     public void testAddDefault()
     {
@@ -291,7 +291,7 @@
     }
 
     /**
-     * Tests the dropping of a column default value.
+     * Tests the removal of a column default value.
      */
     public void testDropDefault()
     {
@@ -327,10 +327,15 @@
     }
 
     /**
-     * Tests the making a column auto-increment.
+     * Tests the change of a column's auto-increment state.
      */
     public void testMakeAutoIncrement()
     {
+        if (!getPlatformInfo().isNonPKIdentityColumnsSupported())
+        {
+            return;
+        }
+        
         final String model1Xml = 
             "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
             "<database name='roundtriptest'>\n"+
@@ -366,10 +371,15 @@
     }
 
     /**
-     * Tests the dropping the column auto-increment status.
+     * Tests the removal the column auto-increment status.
      */
     public void testDropAutoIncrement()
     {
+        if (!getPlatformInfo().isNonPKIdentityColumnsSupported())
+        {
+            return;
+        }
+        
         final String model1Xml = 
             "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
             "<database name='roundtriptest'>\n"+
@@ -402,7 +412,7 @@
     }
 
     /**
-     * Tests the adding a column.
+     * Tests the addition of a column.
      */
     public void testAddColumn()
     {
@@ -418,7 +428,7 @@
             "<database name='roundtriptest'>\n"+
             "  <table name='roundtrip'>\n"+
             "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
-            "    <column name='avalue' type='INTEGER' default='2' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
             "  </table>\n"+
             "</database>";
 
@@ -433,11 +443,122 @@
 
         List beans = getRows("roundtrip");
 
+        assertEquals((Object)null, beans.get(0), "avalue");
+    }
+
+    /**
+     * Tests the addition of several columns.
+     */
+    public void testAddColumns()
+    {
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue3' type='DOUBLE' default='1.0'/>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue1' type='VARCHAR' size='32'/>\n"+
+            "    <column name='avalue2' type='INTEGER' required='true' default='0'/>\n"+
+            "    <column name='avalue3' type='DOUBLE' default='1.0'/>\n"+
+            "    <column name='avalue4' type='CHAR' size='16'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(model1Xml);
+
+        insertRow("roundtrip", new Object[] { new Integer(1), new Double(3.0) });
+
+        alterDatabase(model2Xml);
+
+        assertEquals(getAdjustedModel(),
+                     readModelFromDatabase("roundtriptest"));
+
+        List beans = getRows("roundtrip");
+
+        assertEquals((Object)null, beans.get(0), "avalue1");
+        assertEquals(new Integer(0), beans.get(0), "avalue2");
+        assertEquals((Object)null, beans.get(0), "avalue4");
+    }
+
+    /**
+     * Tests the addition of a column with a default value.
+     */
+    public void testAddColumnWithDefault()
+    {
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER' default='2'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(model1Xml);
+
+        insertRow("roundtrip", new Object[] { new Integer(1) });
+
+        alterDatabase(model2Xml);
+
+        assertEquals(getAdjustedModel(),
+                     readModelFromDatabase("roundtriptest"));
+
+        List beans = getRows("roundtrip");
+
+        assertEquals(new Integer(2), beans.get(0), "avalue");
+    }
+
+    /**
+     * Tests the addition of a column that is set to NOT NULL.
+     */
+    public void testAddRequiredColumn()
+    {
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER' default='2' required='true'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(model1Xml);
+
+        insertRow("roundtrip", new Object[] { new Integer(1) });
+
+        alterDatabase(model2Xml);
+
+        assertEquals(getAdjustedModel(),
+                     readModelFromDatabase("roundtriptest"));
+
+        List beans = getRows("roundtrip");
+
         assertEquals(new Integer(2), beans.get(0), "avalue");
     }
 
     /**
-     * Tests the dropping a column.
+     * Tests the removal of a column.
      */
     public void testDropColumn()
     {
@@ -472,7 +593,7 @@
     }
 
     /**
-     * Tests the adding a column to the pk.
+     * Tests the addition of a column to the pk.
      */
     public void testAddColumnToPK()
     {
@@ -508,7 +629,7 @@
     }
 
     /**
-     * Tests the removing a column from the pk.
+     * Tests the removal of a column from the pk.
      */
     public void testRemoveColumnFromPK()
     {
@@ -544,7 +665,7 @@
     }
 
     /**
-     * Tests the adding a pk column.
+     * Tests the addition of a pk column.
      */
     public void testAddPKColumn()
     {
@@ -579,7 +700,7 @@
     }
 
     /**
-     * Tests the adding a primary key and a column.
+     * Tests the addition of a primary key and a column.
      */
     public void testAddPKAndColumn()
     {
@@ -614,7 +735,7 @@
     }
 
     /**
-     * Tests the adding a primary key and a primary key column.
+     * Tests the addition of a primary key and a primary key column.
      */
     public void testAddPKAndPKColumn()
     {
@@ -649,7 +770,7 @@
     }
 
     /**
-     * Tests the dropping of a pk column.
+     * Tests the removal of a pk column.
      */
     public void testDropPKColumn()
     {
@@ -684,7 +805,7 @@
     }
 
     /**
-     * Tests the adding of an index.
+     * Tests the addition of an index.
      */
     public void testAddIndex()
     {
@@ -727,7 +848,7 @@
     }
 
     /**
-     * Tests the adding of an unique index.
+     * Tests the addition of an unique index.
      */
     public void testAddUniqueIndex()
     {
@@ -766,7 +887,7 @@
     }
 
     /**
-     * Tests the dropping of an unique index.
+     * Tests the removal of an unique index.
      */
     public void testDropUniqueIndex()
     {
@@ -809,7 +930,7 @@
     }
 
     /**
-     * Tests the adding of a column to an index.
+     * Tests the addition of a column to an index.
      */
     public void testAddColumnToIndex()
     {
@@ -855,7 +976,7 @@
     }
 
     /**
-     * Tests the removing of a column from an index.
+     * Tests the removal of a column from an index.
      */
     public void testRemoveColumnFromUniqueIndex()
     {
@@ -901,7 +1022,7 @@
     }
 
     /**
-     * Tests the adding a foreign key.
+     * Tests the addition of a foreign key.
      */
     public void testAddFK()
     {
@@ -950,7 +1071,7 @@
     }
 
     /**
-     * Tests the dropping of a foreign key.
+     * Tests the removal of a foreign key.
      */
     public void testDropFK()
     {
@@ -1006,7 +1127,7 @@
     }
 
     /**
-     * Tests the adding a reference to a foreign key.
+     * Tests the addition of a reference to a foreign key.
      */
     public void testAddReferenceToFK()
     {
@@ -1063,7 +1184,7 @@
     }
 
     /**
-     * Tests the removing a reference from a foreign key.
+     * Tests the removal of a reference from a foreign key.
      */
     public void testRemoveReferenceFromFK()
     {
@@ -1118,7 +1239,7 @@
     }
 
     /**
-     * Tests the adding a table.
+     * Tests the addition of a table.
      */
     public void testAddTable1()
     {
@@ -1159,7 +1280,7 @@
     }
 
     /**
-     * Tests the adding a table.
+     * Tests the addition of a table.
      */
     public void testAddTable2()
     {
@@ -1224,7 +1345,7 @@
     }
 
     /**
-     * Tests the removing a table.
+     * Tests the removal of a table.
      */
     public void testRemoveTable1()
     {
@@ -1263,7 +1384,7 @@
     }
 
     /**
-     * Tests the removing a table.
+     * Tests the removal of a table.
      */
     public void testRemoveTable2()
     {