Added support for specification of which tables to remove (DDLUTILS-180, DDLUTILS-87)

git-svn-id: https://svn.apache.org/repos/asf/db/ddlutils/trunk@635228 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/ddlutils/alteration/RemoveTablesChange.java b/src/java/org/apache/ddlutils/alteration/RemoveTablesChange.java
new file mode 100644
index 0000000..51c7aac
--- /dev/null
+++ b/src/java/org/apache/ddlutils/alteration/RemoveTablesChange.java
@@ -0,0 +1,131 @@
+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.ArrayList;

+import java.util.Iterator;

+import java.util.regex.Pattern;

+

+import org.apache.ddlutils.model.Database;

+import org.apache.ddlutils.model.ForeignKey;

+import org.apache.ddlutils.model.Table;

+

+/**

+ * Represents the removal of tables and foreign keys to them, from a model.

+ * 

+ * @version $Revision: $

+ */

+public class RemoveTablesChange implements ModelChange

+{

+    /** The names of the tables to be removed. */

+    private String[] _tableNames;

+    /** The regular expression matching the names of the tables to be removed. */

+    private Pattern _tableNameRegExp;

+

+    /**

+     * Creates a new change object.

+     * 

+     * @param tableNames The names of the tables to be removed

+     */

+    public RemoveTablesChange(String[] tableNames)

+    {

+        _tableNames = new String[tableNames.length];

+        System.arraycopy(tableNames, 0, _tableNames, 0, tableNames.length);

+    }

+

+    /**

+     * Creates a new change object.

+     * 

+     * @param tableNameRegExp The regular expression matching the names of the tables

+     *                        to be removed (see {@link java.util.regex.Pattern}

+     *                        for details); for case insensitive matching, an uppercase

+     *                        name can be assumed

+     */

+    public RemoveTablesChange(String tableNameRegExp)

+    {

+        _tableNameRegExp = Pattern.compile(tableNameRegExp);

+    }

+

+    /**

+     * {@inheritDoc}

+     */

+    public void apply(Database model, boolean caseSensitive)

+    {

+        ArrayList tables = new ArrayList();

+

+        if (_tableNames != null)

+        {

+            for (int idx = 0; idx < _tableNames.length; idx++)

+            {

+                Table table = model.findTable(_tableNames[idx], caseSensitive);

+

+                if (table != null)

+                {

+                    tables.add(table);

+                }

+            }

+        }

+        else if (_tableNameRegExp != null)

+        {

+            for (int idx = 0; idx < model.getTableCount(); idx++)

+            {

+                Table  table     = model.getTable(idx);

+                String tableName = table.getName();

+

+                if (!caseSensitive)

+                {

+                    tableName = tableName.toUpperCase();

+                }

+                if (_tableNameRegExp.matcher(tableName).matches())

+                {

+                    tables.add(table);

+                }

+            }

+        }

+        for (Iterator tableIt = tables.iterator(); tableIt.hasNext();)

+        {

+            Table targetTable = (Table)tableIt.next();

+            

+            for (int tableIdx = 0; tableIdx < model.getTableCount(); tableIdx++)

+            {

+                Table     curTable    = model.getTable(tableIdx);

+                ArrayList fksToRemove = new ArrayList();

+

+                for (int fkIdx = 0; fkIdx < curTable.getForeignKeyCount(); fkIdx++)

+                {

+                    ForeignKey curFk = curTable.getForeignKey(fkIdx);

+

+                    if (curFk.getForeignTable().equals(targetTable))

+                    {

+                        fksToRemove.add(curFk);

+                    }

+                }

+                for (Iterator fkIt = fksToRemove.iterator(); fkIt.hasNext();)

+                {

+                    curTable.removeForeignKey((ForeignKey)fkIt.next());

+                }

+            }

+        }

+        for (Iterator tableIt = tables.iterator(); tableIt.hasNext();)

+        {

+            model.removeTable((Table)tableIt.next());

+        }

+    }

+}

diff --git a/src/java/org/apache/ddlutils/task/DropTablesCommand.java b/src/java/org/apache/ddlutils/task/DropTablesCommand.java
index d69f381..6bf6b65 100644
--- a/src/java/org/apache/ddlutils/task/DropTablesCommand.java
+++ b/src/java/org/apache/ddlutils/task/DropTablesCommand.java
@@ -19,8 +19,12 @@
  * under the License.

  */

 

+import java.util.ArrayList;

+

 import org.apache.commons.dbcp.BasicDataSource;

 import org.apache.ddlutils.Platform;

+import org.apache.ddlutils.alteration.RemoveTablesChange;

+import org.apache.ddlutils.model.CloneHelper;

 import org.apache.ddlutils.model.Database;

 import org.apache.tools.ant.BuildException;

 

@@ -32,6 +36,73 @@
  */

 public class DropTablesCommand extends DatabaseCommand

 {

+    /** The names of the tables to be dropped. */

+    private String[] _tableNames; 

+    /** The regular expression matching the names of the tables to be dropped. */

+    private String _tableNameRegExp;

+

+    /**

+     * Sets the names of the tables to be removed, as a comma-separated list. Escape a

+     * comma via '\,' if it is part of the table name. Please note that table names are

+     * not trimmed which means that whitespace characters should only be present in

+     * this string if they are actually part of the table name (i.e. in delimited

+     * identifer mode).

+     * 

+     * @param tableNameList The comma-separated list of table names

+     * @ant.not-required If no table filter is specified, then all tables will be dropped.

+     */

+    public void setTableNames(String tableNameList)

+    {

+        String[]  tmpTableNames = tableNameList.split(",");

+        ArrayList tableNames    = new ArrayList();

+        String    last          = null;

+

+        for (int idx = 0; idx < tmpTableNames.length; idx++)

+        {

+            String  str         = tmpTableNames[idx];

+            int     strLen      = str.length();

+            boolean endsInSlash = (strLen > 0) && (str.charAt(strLen - 1) == '\\') &&

+                                  ((strLen == 1) || (str.charAt(strLen - 2) != '\\'));

+

+            if (last != null)

+            {

+                last += "," + str;

+                if (!endsInSlash)

+                {

+                    tableNames.add(last);

+                    last = null;

+                }

+            }

+            else if (endsInSlash)

+            {

+                last = str.substring(0, strLen - 1);

+            }

+            else

+            {

+                tableNames.add(str);

+            }

+        }

+        if (last != null)

+        {

+            tableNames.add(last + ",");

+        }

+        _tableNames = (String[])tableNames.toArray(new String[tableNames.size()]);

+    }

+

+    /**

+     * Sets the regular expression matching the names of the tables to be removed.

+     * For case insensitive matching, an uppercase name can be assumed. If no

+     * regular expressionis specified

+     * 

+     * @param tableNameRegExp The regular expression; see {@link java.util.regex.Pattern}

+     *                        for details

+     * @ant.not-required If no table filter is specified, then all tables will be dropped.

+     */

+    public void setTableNameRegExp(String tableNameRegExp)

+    {

+        _tableNameRegExp = tableNameRegExp;

+    }

+

     /**

      * {@inheritDoc}

      */

@@ -55,6 +126,15 @@
         Platform platform    = getPlatform();

         Database targetModel = new Database();

 

+        if ((_tableNames != null) || (_tableNameRegExp != null))

+        {

+            RemoveTablesChange change = _tableNames != null ? new RemoveTablesChange(_tableNames)

+                                                            : new RemoveTablesChange(_tableNameRegExp);

+

+            targetModel = new CloneHelper().clone(model);

+            targetModel.initialize();

+            change.apply(targetModel, task.isUseDelimitedSqlIdentifiers());

+        }

         try

         {

             platform.alterModel(model, targetModel, isFailOnError());

diff --git a/src/test/org/apache/ddlutils/TestDatabaseWriterBase.java b/src/test/org/apache/ddlutils/TestDatabaseWriterBase.java
index ce41dfb..5523f2a 100644
--- a/src/test/org/apache/ddlutils/TestDatabaseWriterBase.java
+++ b/src/test/org/apache/ddlutils/TestDatabaseWriterBase.java
@@ -26,6 +26,7 @@
 import java.sql.Connection;

 import java.sql.ResultSet;

 import java.sql.Statement;

+import java.sql.Types;

 import java.util.ArrayList;

 import java.util.Iterator;

 import java.util.List;

@@ -42,8 +43,13 @@
 import org.apache.commons.dbcp.BasicDataSource;

 import org.apache.ddlutils.io.DataReader;

 import org.apache.ddlutils.io.DataToDatabaseSink;

+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.Table;

 import org.apache.ddlutils.platform.CreationParameters;

+import org.apache.ddlutils.platform.DefaultValueHelper;

 import org.apache.ddlutils.platform.firebird.FirebirdPlatform;

 import org.apache.ddlutils.platform.interbase.InterbasePlatform;

 

@@ -555,7 +561,112 @@
 

     	return getPlatform().readModelFromDatabase(databaseName, catalog, schema, null);

     }

-    

+

+    /**

+     * Returns a copy of the given model adjusted for type changes because of the native type mappings

+     * which when read back from the database will map to different types.

+     * 

+     * @param sourceModel The source model

+     * @return The adjusted model

+     */

+    protected Database adjustModel(Database sourceModel)

+    {

+        Database model = new CloneHelper().clone(sourceModel);

+

+        for (int tableIdx = 0; tableIdx < model.getTableCount(); tableIdx++)

+        {

+            Table table = model.getTable(tableIdx);

+

+            for (int columnIdx = 0; columnIdx < table.getColumnCount(); columnIdx++)

+            {

+                Column column     = table.getColumn(columnIdx);

+                int    origType   = column.getTypeCode();

+                int    targetType = getPlatformInfo().getTargetJdbcType(origType);

+

+                // we adjust the column types if the native type would back-map to a

+                // different jdbc type

+                if (targetType != origType)

+                {

+                    column.setTypeCode(targetType);

+                    // we should also adapt the default value

+                    if (column.getDefaultValue() != null)

+                    {

+                        DefaultValueHelper helper = getPlatform().getSqlBuilder().getDefaultValueHelper();

+

+                        column.setDefaultValue(helper.convert(column.getDefaultValue(), origType, targetType));

+                    }

+                }

+                // we also promote the default size if the column has no size

+                // spec of its own

+                if ((column.getSize() == null) && getPlatformInfo().hasSize(targetType))

+                {

+                    Integer defaultSize = getPlatformInfo().getDefaultSize(targetType);

+

+                    if (defaultSize != null)

+                    {

+                        column.setSize(defaultSize.toString());

+                    }

+                }

+                // finally the platform might return a synthetic default value if the column

+                // is a primary key column

+                if (getPlatformInfo().isSyntheticDefaultValueForRequiredReturned() &&

+                    (column.getDefaultValue() == null) && column.isRequired() && !column.isAutoIncrement())

+                {

+                    switch (column.getTypeCode())

+                    {

+                        case Types.TINYINT:

+                        case Types.SMALLINT:

+                        case Types.INTEGER:

+                        case Types.BIGINT:

+                            column.setDefaultValue("0");

+                            break;

+                        case Types.REAL:

+                        case Types.FLOAT:

+                        case Types.DOUBLE:

+                            column.setDefaultValue("0.0");

+                            break;

+                        case Types.BIT:

+                            column.setDefaultValue("false");

+                            break;

+                        default:

+                            column.setDefaultValue("");

+                            break;

+                    }

+                }

+                if (column.isPrimaryKey() && getPlatformInfo().isPrimaryKeyColumnAutomaticallyRequired())

+                {

+                    column.setRequired(true);

+                }

+                if (column.isAutoIncrement() && getPlatformInfo().isIdentityColumnAutomaticallyRequired())

+                {

+                    column.setRequired(true);

+                }

+            }

+            // we also add the default names to foreign keys that are initially unnamed

+            for (int fkIdx = 0; fkIdx < table.getForeignKeyCount(); fkIdx++)

+            {

+                ForeignKey fk = table.getForeignKey(fkIdx);

+

+                if (fk.getName() == null)

+                {

+                    fk.setName(getPlatform().getSqlBuilder().getForeignKeyName(table, fk));

+                }

+            }

+        }

+        return model;

+    }

+

+    /**

+     * Returns the original model adjusted for type changes because of the native type mappings

+     * which when read back from the database will map to different types.

+     * 

+     * @return The adjusted model

+     */

+    protected Database getAdjustedModel()

+    {

+        return adjustModel(getModel());

+    }

+

     /**

      * Returns the SQL for altering the live database so that it matches the given model.

      * 

diff --git a/src/test/org/apache/ddlutils/io/RoundtripTestBase.java b/src/test/org/apache/ddlutils/io/RoundtripTestBase.java
index 9ec2802..18eb04d 100644
--- a/src/test/org/apache/ddlutils/io/RoundtripTestBase.java
+++ b/src/test/org/apache/ddlutils/io/RoundtripTestBase.java
@@ -36,7 +36,6 @@
 import org.apache.ddlutils.dynabean.SqlDynaClass;

 import org.apache.ddlutils.dynabean.SqlDynaProperty;

 import org.apache.ddlutils.model.CascadeActionEnum;

-import org.apache.ddlutils.model.CloneHelper;

 import org.apache.ddlutils.model.Column;

 import org.apache.ddlutils.model.Database;

 import org.apache.ddlutils.model.ForeignKey;

@@ -45,7 +44,6 @@
 import org.apache.ddlutils.model.Reference;

 import org.apache.ddlutils.model.Table;

 import org.apache.ddlutils.model.TypeMap;

-import org.apache.ddlutils.platform.DefaultValueHelper;

 

 /**

  * Base class for database roundtrip (creation & reconstruction from the database).

@@ -262,99 +260,6 @@
     }

 

     /**

-     * Returns the original model adjusted for type changes because of the native type mappings

-     * which when read back from the database will map to different types.

-     * 

-     * @return The adjusted model

-     */

-    protected Database getAdjustedModel()

-    {

-        Database model = new CloneHelper().clone(getModel());

-

-        for (int tableIdx = 0; tableIdx < model.getTableCount(); tableIdx++)

-        {

-            Table table = model.getTable(tableIdx);

-

-            for (int columnIdx = 0; columnIdx < table.getColumnCount(); columnIdx++)

-            {

-                Column column     = table.getColumn(columnIdx);

-                int    origType   = column.getTypeCode();

-                int    targetType = getPlatformInfo().getTargetJdbcType(origType);

-

-                // we adjust the column types if the native type would back-map to a

-                // different jdbc type

-                if (targetType != origType)

-                {

-                    column.setTypeCode(targetType);

-                    // we should also adapt the default value

-                    if (column.getDefaultValue() != null)

-                    {

-                        DefaultValueHelper helper = getPlatform().getSqlBuilder().getDefaultValueHelper();

-

-                        column.setDefaultValue(helper.convert(column.getDefaultValue(), origType, targetType));

-                    }

-                }

-                // we also promote the default size if the column has no size

-                // spec of its own

-                if ((column.getSize() == null) && getPlatformInfo().hasSize(targetType))

-                {

-                    Integer defaultSize = getPlatformInfo().getDefaultSize(targetType);

-

-                    if (defaultSize != null)

-                    {

-                        column.setSize(defaultSize.toString());

-                    }

-                }

-                // finally the platform might return a synthetic default value if the column

-                // is a primary key column

-                if (getPlatformInfo().isSyntheticDefaultValueForRequiredReturned() &&

-                    (column.getDefaultValue() == null) && column.isRequired() && !column.isAutoIncrement())

-                {

-                    switch (column.getTypeCode())

-                    {

-                        case Types.TINYINT:

-                        case Types.SMALLINT:

-                        case Types.INTEGER:

-                        case Types.BIGINT:

-                            column.setDefaultValue("0");

-                            break;

-                        case Types.REAL:

-                        case Types.FLOAT:

-                        case Types.DOUBLE:

-                            column.setDefaultValue("0.0");

-                            break;

-                        case Types.BIT:

-                            column.setDefaultValue("false");

-                            break;

-                        default:

-                            column.setDefaultValue("");

-                            break;

-                    }

-                }

-                if (column.isPrimaryKey() && getPlatformInfo().isPrimaryKeyColumnAutomaticallyRequired())

-                {

-                    column.setRequired(true);

-                }

-                if (column.isAutoIncrement() && getPlatformInfo().isIdentityColumnAutomaticallyRequired())

-                {

-                    column.setRequired(true);

-                }

-            }

-            // we also add the default names to foreign keys that are initially unnamed

-            for (int fkIdx = 0; fkIdx < table.getForeignKeyCount(); fkIdx++)

-            {

-                ForeignKey fk = table.getForeignKey(fkIdx);

-

-                if (fk.getName() == null)

-                {

-                    fk.setName(getPlatform().getSqlBuilder().getForeignKeyName(table, fk));

-                }

-            }

-        }

-        return model;

-    }

-

-    /**

      * Compares the specified attribute value of the given bean with the expected object.

      * 

      * @param expected The expected object

diff --git a/src/test/org/apache/ddlutils/task/TestDropTablesCommand.java b/src/test/org/apache/ddlutils/task/TestDropTablesCommand.java
index c6d3bda..b5fdedb 100644
--- a/src/test/org/apache/ddlutils/task/TestDropTablesCommand.java
+++ b/src/test/org/apache/ddlutils/task/TestDropTablesCommand.java
@@ -253,5 +253,650 @@
                      readModelFromDatabase("roundtriptest"));
     }
 
-    // circular fks
+    /**
+     * Tests the removal of a table via the names list. 
+     */
+    public void testNamesListWithSingleName()
+    {
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("roundtrip1");
+        task.addDropTables(subTask);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of multiple tables via the names list. 
+     */
+    public void testNamesListWithMultipleNames()
+    {
+        final String modelXml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(modelXml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("roundtrip1,roundtrip2,roundtrip3");
+        task.addDropTables(subTask);
+        task.execute();
+
+        assertEquals(new Database("roundtriptest"),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of a table via the names list. 
+     */
+    public void testNamesListWithSingleDelimitedName()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip 2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("Roundtrip 1");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of multiple tables via the names list. 
+     */
+    public void testNamesListWithMultipleDelimitedNames()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String modelXml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip 2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(modelXml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("Roundtrip 2,Roundtrip 1");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(new Database("roundtriptest"),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of a table via the names list. 
+     */
+    public void testNamesListWithSingleDelimitedNameWithComma()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip, 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip, 2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip, 2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip, 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip, 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("Roundtrip\\, 2");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of a table via the names list. 
+     */
+    public void testNamesListWithSingleDelimitedNameEndingInComma()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 2,'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip 2,'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("Roundtrip 2\\,");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of multiple tables via the names list. 
+     */
+    public void testNamesListWithMultipleDelimitedNameWithCommas()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String modelXml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip, 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 2,'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip 2,'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip, 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(modelXml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("Roundtrip\\, 1,Roundtrip 2\\,");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(new Database("roundtriptest"),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests an empty names list. 
+     */
+    public void testEmptyNamesList()
+    {
+        final String modelXml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(modelXml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNames("");
+        task.addDropTables(subTask);
+        task.execute();
+
+        assertEquals(getAdjustedModel(),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of a table via a regular expression. 
+     */
+    public void testSimpleRegExp()
+    {
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNameRegExp(".*2");
+        task.addDropTables(subTask);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of a table via a regular expression. 
+     */
+    public void testRegExpInDelimitedIdentifierMode()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip 2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNameRegExp(".*\\s[2|3]");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of multiple tables via a regular expression. 
+     */
+    public void testRegExpMultipleTables()
+    {
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrap3'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrap3'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNameRegExp(".*trip.*");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests the removal of multiple tables via a regular expression. 
+     */
+    public void testRegExpMultipleTablesInDelimitedIdentifierMode()
+    {
+        if (!getPlatformInfo().isDelimitedIdentifiersSupported())
+        {
+            return;
+        }
+
+        final String model1Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip 1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip 2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='Roundtrip A'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='Roundtrip 1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String model2Xml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='Roundtrip A'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        getPlatform().setDelimitedIdentifierModeOn(true);
+        createDatabase(model1Xml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNameRegExp(".*\\d");
+        task.addDropTables(subTask);
+        task.setUseDelimitedSqlIdentifiers(true);
+        task.execute();
+
+        assertEquals(adjustModel(parseDatabaseFromString(model2Xml)),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests a regular expression that matches nothing. 
+     */
+    public void testRegExpMatchingNothing()
+    {
+        final String modelXml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(modelXml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNameRegExp(".*\\s\\D");
+        task.addDropTables(subTask);
+        task.execute();
+
+        assertEquals(getAdjustedModel(),
+                     readModelFromDatabase("roundtriptest"));
+    }
+
+    /**
+     * Tests an empty regular expression. 
+     */
+    public void testEmptyRegExp()
+    {
+        final String modelXml = 
+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+            "<database name='roundtriptest'>\n"+
+            "  <table name='roundtrip1'>\n"+
+            "    <column name='pk' type='VARCHAR' size='32' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='INTEGER'/>\n"+
+            "    <foreign-key foreignTable='roundtrip2'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "  <table name='roundtrip2'>\n"+
+            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+
+            "    <column name='avalue' type='VARCHAR' size='32'/>\n"+
+            "    <foreign-key foreignTable='roundtrip1'>\n"+
+            "      <reference local='avalue' foreign='pk'/>\n"+
+            "    </foreign-key>\n"+
+            "  </table>\n"+
+            "</database>";
+
+        createDatabase(modelXml);
+
+        DatabaseToDdlTask task    = getDatabaseToDdlTaskInstance();
+        DropTablesCommand subTask = new DropTablesCommand();
+
+        subTask.setTableNameRegExp("");
+        task.addDropTables(subTask);
+        task.execute();
+
+        assertEquals(getAdjustedModel(),
+                     readModelFromDatabase("roundtriptest"));
+    }
 }