Added equivalence for on delete/on update settings

git-svn-id: https://svn.apache.org/repos/asf/db/ddlutils/trunk@894556 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/ddlutils/PlatformInfo.java b/src/main/java/org/apache/ddlutils/PlatformInfo.java
index e1b04a7..b414ae6 100644
--- a/src/main/java/org/apache/ddlutils/PlatformInfo.java
+++ b/src/main/java/org/apache/ddlutils/PlatformInfo.java
@@ -24,6 +24,7 @@
 import java.util.Arrays;

 import java.util.HashMap;

 import java.util.HashSet;

+import java.util.Set;

 

 import org.apache.commons.logging.Log;

 import org.apache.commons.logging.LogFactory;

@@ -180,6 +181,12 @@
     /** Contains the supported ON DELETE actions. */

     private HashSet _supportedOnDeleteActions = new HashSet();

 

+    /** Contains for each ON UPDATE action the list of equivalent actions. */

+    private HashMap _equivalentOnUpdateActions = new HashMap();

+

+    /** Contains for each ON DELETE action the list of equivalent actions. */

+    private HashMap _equivalentOnDeleteActions = new HashMap();

+

     /**

      * Creates a new platform info object.

      */

@@ -1276,4 +1283,92 @@
     {

         _defaultOnDeleteAction = defaultOnDeleteAction;

     }

+

+    /**

+     * Registers the given pair of ON UPDATE actions to be equivalent. Equivalent actions will not

+     * cause a foreign key to be changed/recreated when altering a database.

+     * 

+     * @param actionA The first action

+     * @param actionB The second action

+     */

+    public void addEquivalentOnUpdateActions(CascadeActionEnum actionA, CascadeActionEnum actionB)

+    {

+        if (!actionA.equals(actionB))

+        {

+            Set actionsEquivalentToActionA = (Set)_equivalentOnUpdateActions.get(actionA);

+            Set actionsEquivalentToActionB = (Set)_equivalentOnUpdateActions.get(actionB);

+

+            if (actionsEquivalentToActionA == null)

+            {

+                actionsEquivalentToActionA = new HashSet();

+                _equivalentOnUpdateActions.put(actionA, actionsEquivalentToActionA);

+            }

+            if (actionsEquivalentToActionB == null)

+            {

+                actionsEquivalentToActionB = new HashSet();

+                _equivalentOnUpdateActions.put(actionB, actionsEquivalentToActionB);

+            }

+            actionsEquivalentToActionA.add(actionB);

+            actionsEquivalentToActionB.add(actionA);

+        }

+    }

+

+    /**

+     * Determiones whether the two ON UPDATE actions are equivalent. Equivalent actions will not

+     * cause a foreign key to be changed/recreated when altering a database.

+     * 

+     * @param actionA The first action

+     * @param actionB The second action

+     * @return <code>true</code> if the two actions are equivalent 

+     */

+    public boolean areEquivalentOnUpdateActions(CascadeActionEnum actionA, CascadeActionEnum actionB)

+    {

+        Set actionsEquivalentToActionA = (Set)_equivalentOnUpdateActions.get(actionA);

+

+        return actionsEquivalentToActionA == null ? false : actionsEquivalentToActionA.contains(actionB);

+    }

+

+    /**

+     * Registers the given pair of ON DELETE actions to be equivalent. Equivalent actions will not

+     * cause a foreign key to be changed/recreated when altering a database.

+     * 

+     * @param actionA The first action

+     * @param actionB The second action

+     */

+    public void addEquivalentOnDeleteActions(CascadeActionEnum actionA, CascadeActionEnum actionB)

+    {

+        if (!actionA.equals(actionB))

+        {

+            Set actionsEquivalentToActionA = (Set)_equivalentOnDeleteActions.get(actionA);

+            Set actionsEquivalentToActionB = (Set)_equivalentOnDeleteActions.get(actionB);

+

+            if (actionsEquivalentToActionA == null)

+            {

+                actionsEquivalentToActionA = new HashSet();

+                _equivalentOnDeleteActions.put(actionA, actionsEquivalentToActionA);

+            }

+            if (actionsEquivalentToActionB == null)

+            {

+                actionsEquivalentToActionB = new HashSet();

+                _equivalentOnDeleteActions.put(actionB, actionsEquivalentToActionB);

+            }

+            actionsEquivalentToActionA.add(actionB);

+            actionsEquivalentToActionB.add(actionA);

+        }

+    }

+

+    /**

+     * Determiones whether the two ON DELETE actions are equivalent. Equivalent actions will not

+     * cause a foreign key to be changed/recreated when altering a database.

+     * 

+     * @param actionA The first action

+     * @param actionB The second action

+     * @return <code>true</code> if the two actions are equivalent 

+     */

+    public boolean areEquivalentOnDeleteActions(CascadeActionEnum actionA, CascadeActionEnum actionB)

+    {

+        Set actionsEquivalentToActionA = (Set)_equivalentOnDeleteActions.get(actionA);

+

+        return actionsEquivalentToActionA == null ? false : actionsEquivalentToActionA.contains(actionB);

+    }

 }

diff --git a/src/main/java/org/apache/ddlutils/alteration/ModelComparator.java b/src/main/java/org/apache/ddlutils/alteration/ModelComparator.java
index 13817dd..3a88eef 100644
--- a/src/main/java/org/apache/ddlutils/alteration/ModelComparator.java
+++ b/src/main/java/org/apache/ddlutils/alteration/ModelComparator.java
@@ -373,6 +373,7 @@
         tableDefinitionChanges.addAll(checkForAddedColumns(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));

         tableDefinitionChanges.addAll(checkForPrimaryKeyChanges(sourceModel, sourceTable, intermediateModel, intermediateTable, targetModel, targetTable));

 

+        // TOOD: check for foreign key changes (on delete/on update)

         if (!tableDefinitionChanges.isEmpty())

         {

             if ((_tableDefCangePredicate == null) || _tableDefCangePredicate.areSupported(tmpTable, tableDefinitionChanges))

diff --git a/src/main/java/org/apache/ddlutils/platform/JdbcModelReader.java b/src/main/java/org/apache/ddlutils/platform/JdbcModelReader.java
index ee72b14..667b635 100644
--- a/src/main/java/org/apache/ddlutils/platform/JdbcModelReader.java
+++ b/src/main/java/org/apache/ddlutils/platform/JdbcModelReader.java
@@ -933,12 +933,11 @@
             CascadeActionEnum onUpdateAction = convertAction((Short)values.get("UPDATE_RULE"));
             CascadeActionEnum onDeleteAction = convertAction((Short)values.get("DELETE_RULE"));
 
-            // Some JDBC drivers lie and return actions that the DB not actually supports
-            if ((onUpdateAction == null) || !getPlatformInfo().isActionSupportedForOnUpdate(onUpdateAction))
+            if (onUpdateAction == null)
             {
                 onUpdateAction = getPlatformInfo().getDefaultOnUpdateAction();
             }
-            if ((onDeleteAction == null) || !getPlatformInfo().isActionSupportedForOnDelete(onDeleteAction))
+            if (onDeleteAction == null)
             {
                 onDeleteAction = getPlatformInfo().getDefaultOnDeleteAction();
             }
diff --git a/src/main/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java b/src/main/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java
index 1f7e09a..aa32e44 100644
--- a/src/main/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java
+++ b/src/main/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java
@@ -64,8 +64,11 @@
         info.addNativeTypeMapping(Types.DOUBLE, "DOUBLE");

         info.addNativeTypeMapping(Types.FLOAT,  "DOUBLE", Types.DOUBLE);

         info.setSupportedOnUpdateActions(new CascadeActionEnum[] { CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT });

+        info.setDefaultOnUpdateAction(CascadeActionEnum.NONE);

+        info.addEquivalentOnUpdateActions(CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT);

         info.setSupportedOnDeleteActions(new CascadeActionEnum[] { CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT,

                                                                    CascadeActionEnum.CASCADE, CascadeActionEnum.SET_NULL });

+        info.setDefaultOnDeleteAction(CascadeActionEnum.NONE);

 

         setSqlBuilder(new DerbyBuilder(this));

         setModelReader(new DerbyModelReader(this));

diff --git a/src/main/java/org/apache/ddlutils/platform/mssql/MSSqlPlatform.java b/src/main/java/org/apache/ddlutils/platform/mssql/MSSqlPlatform.java
index ada4af1..6af9a2d 100644
--- a/src/main/java/org/apache/ddlutils/platform/mssql/MSSqlPlatform.java
+++ b/src/main/java/org/apache/ddlutils/platform/mssql/MSSqlPlatform.java
@@ -77,7 +77,9 @@
         info.setIdentityColumnAutomaticallyRequired(true);

         info.setMultipleIdentityColumnsSupported(false);

         info.setSupportedOnUpdateActions(new CascadeActionEnum[] { CascadeActionEnum.CASCADE, CascadeActionEnum.NONE });

+        info.addEquivalentOnUpdateActions(CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT);

         info.setSupportedOnDeleteActions(new CascadeActionEnum[] { CascadeActionEnum.CASCADE, CascadeActionEnum.NONE });

+        info.addEquivalentOnDeleteActions(CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT);

 

         info.addNativeTypeMapping(Types.ARRAY,         "IMAGE",         Types.LONGVARBINARY);

         // BIGINT will be mapped back to BIGINT by the model reader 

diff --git a/src/main/java/org/apache/ddlutils/platform/oracle/Oracle8Platform.java b/src/main/java/org/apache/ddlutils/platform/oracle/Oracle8Platform.java
index 4795c3c..2b27338 100644
--- a/src/main/java/org/apache/ddlutils/platform/oracle/Oracle8Platform.java
+++ b/src/main/java/org/apache/ddlutils/platform/oracle/Oracle8Platform.java
@@ -74,6 +74,7 @@
         info.setPrimaryKeyColumnAutomaticallyRequired(true);

         info.setSupportedOnUpdateActions(new CascadeActionEnum[] { CascadeActionEnum.NONE });

         info.setSupportedOnDeleteActions(new CascadeActionEnum[] { CascadeActionEnum.CASCADE, CascadeActionEnum.SET_NULL, CascadeActionEnum.NONE });

+        info.addEquivalentOnDeleteActions(CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT);

 

         // Note that the back-mappings are partially done by the model reader, not the driver

         info.addNativeTypeMapping(Types.ARRAY,         "BLOB",             Types.BLOB);

diff --git a/src/main/java/org/apache/ddlutils/platform/sapdb/SapDbPlatform.java b/src/main/java/org/apache/ddlutils/platform/sapdb/SapDbPlatform.java
index d651915..e3b2a60 100644
--- a/src/main/java/org/apache/ddlutils/platform/sapdb/SapDbPlatform.java
+++ b/src/main/java/org/apache/ddlutils/platform/sapdb/SapDbPlatform.java
@@ -67,9 +67,10 @@
         info.setMultipleIdentityColumnsSupported(false);

         info.setCommentPrefix("/*");

         info.setCommentSuffix("*/");

-        info.setSupportedOnUpdateActions(new CascadeActionEnum[] { CascadeActionEnum.NONE });

-        info.setDefaultOnDeleteAction(CascadeActionEnum.RESTRICT);

         info.setSupportedOnDeleteActions(new CascadeActionEnum[] { CascadeActionEnum.CASCADE, CascadeActionEnum.RESTRICT, CascadeActionEnum.SET_DEFAULT, CascadeActionEnum.SET_NULL, CascadeActionEnum.NONE });

+        info.addEquivalentOnDeleteActions(CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT);

+        info.setSupportedOnUpdateActions(new CascadeActionEnum[] { CascadeActionEnum.NONE });

+        info.addEquivalentOnUpdateActions(CascadeActionEnum.NONE, CascadeActionEnum.RESTRICT);

 

         // BIGINT is also handled by the model reader

         // Unfortunately there is no way to distinguish between REAL, and FLOAT/DOUBLE when

diff --git a/src/test/java/org/apache/ddlutils/TestAgainstLiveDatabaseBase.java b/src/test/java/org/apache/ddlutils/TestAgainstLiveDatabaseBase.java
index 36cde33..49125b5 100644
--- a/src/test/java/org/apache/ddlutils/TestAgainstLiveDatabaseBase.java
+++ b/src/test/java/org/apache/ddlutils/TestAgainstLiveDatabaseBase.java
@@ -53,7 +53,6 @@
 import org.apache.ddlutils.io.DataReader;

 import org.apache.ddlutils.io.DataToDatabaseSink;

 import org.apache.ddlutils.io.DatabaseIO;

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

 import org.apache.ddlutils.model.CloneHelper;

 import org.apache.ddlutils.model.Column;

 import org.apache.ddlutils.model.Database;

@@ -1312,35 +1311,12 @@
                          getPlatform().getSqlBuilder().shortenName(actual.getForeignTableName().toUpperCase(), getSqlBuilder().getMaxTableNameLength()));

         }

 

-        CascadeActionEnum realExpectedOnUpdateAction = expected.getOnUpdate();

-        CascadeActionEnum realActualOnUpdateAction   = actual.getOnUpdate();

-

-        if (!getPlatformInfo().isActionSupportedForOnUpdate(realExpectedOnUpdateAction) || (realExpectedOnUpdateAction == CascadeActionEnum.NONE))

-        {

-            realExpectedOnUpdateAction = getPlatformInfo().getDefaultOnUpdateAction();

-        }

-        if (!getPlatformInfo().isActionSupportedForOnUpdate(realActualOnUpdateAction) || (realActualOnUpdateAction == CascadeActionEnum.NONE))

-        {

-            realActualOnUpdateAction = getPlatformInfo().getDefaultOnUpdateAction();

-        }

-        assertEquals("Not the same onUpdate setting in foreign key "+actual.getName()+".",

-                     realExpectedOnUpdateAction,

-                     realActualOnUpdateAction);

-

-        CascadeActionEnum realExpectedOnDeleteAction = expected.getOnDelete();

-        CascadeActionEnum realActualOnDeleteAction   = actual.getOnDelete();

-

-        if (!getPlatformInfo().isActionSupportedForOnDelete(realExpectedOnDeleteAction) || (realExpectedOnDeleteAction == CascadeActionEnum.NONE))

-        {

-            realExpectedOnDeleteAction = getPlatformInfo().getDefaultOnDeleteAction();

-        }

-        if (!getPlatformInfo().isActionSupportedForOnDelete(realActualOnDeleteAction) || (realActualOnDeleteAction == CascadeActionEnum.NONE))

-        {

-            realActualOnDeleteAction = getPlatformInfo().getDefaultOnDeleteAction();

-        }

-        assertEquals("Not the same onDelete setting in foreign key "+actual.getName()+".",

-                     realExpectedOnDeleteAction,

-                     realActualOnDeleteAction);

+        assertTrue("Not the same onUpdate setting in foreign key "+actual.getName()+": expected = "+expected.getOnUpdate()+", actual = "+actual.getOnUpdate(),

+                   expected.getOnUpdate().equals(actual.getOnUpdate()) ||

+                   getPlatformInfo().areEquivalentOnUpdateActions(expected.getOnUpdate(), actual.getOnUpdate()));

+        assertTrue("Not the same onDelete setting in foreign key "+actual.getName()+": expected = "+expected.getOnDelete()+", actual = "+actual.getOnDelete(),

+                   expected.getOnDelete().equals(actual.getOnDelete()) ||

+                   getPlatformInfo().areEquivalentOnDeleteActions(expected.getOnDelete(), actual.getOnDelete()));

 

         assertEquals("Not the same number of references in foreign key "+actual.getName()+".",

                      expected.getReferenceCount(),

diff --git a/src/test/resources/jdbc.properties.db2 b/src/test/resources/jdbc.properties.db2
index 4ddf2b2..2464fd5 100644
--- a/src/test/resources/jdbc.properties.db2
+++ b/src/test/resources/jdbc.properties.db2
@@ -26,6 +26,6 @@
 datasource.class=org.apache.commons.dbcp.BasicDataSource

 

 datasource.driverClassName=com.ibm.db2.jcc.DB2Driver

-datasource.url=jdbc:db2://192.168.129.134:50000/ddlutils

+datasource.url=jdbc:db2://192.168.129.133:50000/ddlutils

 datasource.username=ddlutils

 datasource.password=ddlutils

diff --git a/src/test/resources/jdbc.properties.firebird b/src/test/resources/jdbc.properties.firebird
index f02cffa..03fa361 100644
--- a/src/test/resources/jdbc.properties.firebird
+++ b/src/test/resources/jdbc.properties.firebird
@@ -29,7 +29,7 @@
 

 datasource.class=org.apache.commons.dbcp.BasicDataSource

 datasource.driverClassName=org.firebirdsql.jdbc.FBDriver

-datasource.url=jdbc:firebirdsql://192.168.129.129/C:/Program Files/Firebird/Firebird_2_0/data/ddlutils.fdb

+datasource.url=jdbc:firebirdsql://192.168.129.133/C:/Program Files/Firebird/Firebird_2_0/data/ddlutils.fdb

 datasource.username=SYSDBA

 datasource.password=masterkey

 

diff --git a/src/test/resources/jdbc.properties.maxdb b/src/test/resources/jdbc.properties.maxdb
index 1f88a04..8d88ea1 100644
--- a/src/test/resources/jdbc.properties.maxdb
+++ b/src/test/resources/jdbc.properties.maxdb
@@ -29,6 +29,6 @@
 

 datasource.class=org.apache.commons.dbcp.BasicDataSource

 datasource.driverClassName=com.sap.dbtech.jdbc.DriverSapDB

-datasource.url=jdbc:sapdb://192.168.129.134/MAXDB1

+datasource.url=jdbc:sapdb://192.168.129.133/MAXDB1

 datasource.username=ddlutils

 datasource.password=ddlutils

diff --git a/src/test/resources/jdbc.properties.oracle10 b/src/test/resources/jdbc.properties.oracle10
index 30932d8..1af9e9a 100644
--- a/src/test/resources/jdbc.properties.oracle10
+++ b/src/test/resources/jdbc.properties.oracle10
@@ -29,7 +29,7 @@
 

 datasource.class=org.apache.commons.dbcp.BasicDataSource

 datasource.driverClassName=oracle.jdbc.driver.OracleDriver

-datasource.url=jdbc:oracle:thin:@192.168.129.134:1521:XE

+datasource.url=jdbc:oracle:thin:@192.168.129.133:1521:XE

 datasource.username=ddlutils

 datasource.password=ddlutils

 

diff --git a/src/test/resources/jdbc.properties.postgresql b/src/test/resources/jdbc.properties.postgresql
index c5332bc..67d9bb9 100644
--- a/src/test/resources/jdbc.properties.postgresql
+++ b/src/test/resources/jdbc.properties.postgresql
@@ -29,7 +29,7 @@
 

 datasource.class=org.apache.commons.dbcp.BasicDataSource

 datasource.driverClassName=org.postgresql.Driver

-datasource.url=jdbc:postgresql://192.168.129.134/ddlutils

+datasource.url=jdbc:postgresql://192.168.129.133/ddlutils

 datasource.username=ddlutils

 datasource.password=ddlutils

 

diff --git a/src/test/resources/jdbc.properties.sqlserver2005 b/src/test/resources/jdbc.properties.sqlserver2005
index 0746a89..a9a665d 100644
--- a/src/test/resources/jdbc.properties.sqlserver2005
+++ b/src/test/resources/jdbc.properties.sqlserver2005
@@ -26,7 +26,7 @@
 datasource.class=org.apache.commons.dbcp.BasicDataSource

 

 datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

-datasource.url=jdbc:sqlserver://192.168.129.134;databaseName=ddlutils;selectMethod=cursor

+datasource.url=jdbc:sqlserver://192.168.129.133;databaseName=ddlutils;selectMethod=cursor

 

 datasource.username=ddlutils

 datasource.password=ddlutils