Fixed update() implementation for primary key updates
Adjusted onUpdate/onDelete tests

git-svn-id: https://svn.apache.org/repos/asf/db/ddlutils/trunk@576220 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/ddlutils/Platform.java b/src/java/org/apache/ddlutils/Platform.java
index 18f9be5..d0e3e57 100644
--- a/src/java/org/apache/ddlutils/Platform.java
+++ b/src/java/org/apache/ddlutils/Platform.java
@@ -815,7 +815,8 @@
     public void insert(Connection connection, Database model, Collection dynaBeans) throws DatabaseOperationException;

 

     /**

-     * Returns the sql for updating the given bean in the database.

+     * Returns the sql for updating the given bean in the database. Note that this method can not be used to

+     * generate SQL for updating primary key columns. 

      * 

      * @param model    The database model to use

      * @param dynaBean The bean

@@ -824,7 +825,19 @@
     public String getUpdateSql(Database model, DynaBean dynaBean);

 

     /**

-     * Updates the given bean in the database, assuming the primary key values are specified.

+     * Returns the sql for updating the given bean in the database. Note that this method can not be used to

+     * generate SQL for updating primary key columns. 

+     * 

+     * @param model       The database model to use

+     * @param oldDynaBean The bean identifying the row to update

+     * @param newDynaBean The bean containing the new values

+     * @return The update sql

+     */

+    public String getUpdateSql(Database model, DynaBean oldDynaBean, DynaBean newDynaBan);

+

+    /**

+     * Updates the given bean in the database, assuming the primary key values are specified. Note that this means

+     * that this method will not update the primary key columns.

      * 

      * @param model    The database model to use

      * @param dynaBean The bean

@@ -832,7 +845,8 @@
     public void update(Database model, DynaBean dynaBean) throws DatabaseOperationException;

 

     /**

-     * Updates the row which maps to the given bean.

+     * Updates the row which maps to the given bean. Note that this means that this method will not update the

+     * primary key columns.

      * 

      * @param connection The database connection

      * @param model      The database model to use

@@ -842,7 +856,7 @@
 

     /**

      * Updates the row identified by the given <code>oldDynaBean</code> in the database with the

-     * values in <code>newDynaBean</code>.

+     * values in <code>newDynaBean</code>. This method can be used to update primary key columns.

      * 

      * @param model       The database model to use

      * @param oldDynaBean The bean identifying the row (which means the primary key fields need to be specified)

@@ -852,7 +866,7 @@
 

     /**

      * Updates the row identified by the given <code>oldDynaBean</code> in the database with the

-     * values in <code>newDynaBean</code>.

+     * values in <code>newDynaBean</code>. This method can be used to update primary key columns.

      * 

      * @param connection  The database connection

      * @param model       The database model to use

diff --git a/src/java/org/apache/ddlutils/PlatformInfo.java b/src/java/org/apache/ddlutils/PlatformInfo.java
index 11842eb..970144d 100644
--- a/src/java/org/apache/ddlutils/PlatformInfo.java
+++ b/src/java/org/apache/ddlutils/PlatformInfo.java
@@ -56,9 +56,6 @@
     /** Whether embedded foreign key constraints are explicitly named. */

     private boolean _embeddedForeignKeysNamed = false;

 

-    /** Whether the set-default action is supportd for onDelete/onUpdate in a foreign key. */

-    private boolean _setDefaultActionSupported = true;

-

     /** Whether non-unique indices are supported. */

     private boolean _indicesSupported = true;

 

@@ -290,28 +287,6 @@
     }

 

     /**

-     * Determines whether the set-default action is supported for onUpdate/onDelete

-     * in foreign keys.

-     *

-     * @return <code>true</code> if set-default is supported

-     */

-    public boolean isSetDefaultActionSupported()

-    {

-        return _setDefaultActionSupported;

-    }

-

-    /**

-     * Specifies whether the set-default action is supported for onUpdate/onDelete

-     * in foreign keys.

-     *

-     * @param setDefaultActionSupported <code>true</code> if set-default is supported

-     */

-    public void setSetDefaultActionSupported(boolean setDefaultActionSupported)

-    {

-        _setDefaultActionSupported = setDefaultActionSupported;

-    }

-

-    /**

      * Determines whether indices are supported.

      *

      * @return <code>true</code> if indices are supported

diff --git a/src/java/org/apache/ddlutils/platform/PlatformImplBase.java b/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
index d52f697..fd93fb5 100644
--- a/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
+++ b/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
@@ -1599,100 +1599,71 @@
     }

 

     /**

-     * {@inheritDoc}

+     * Creates the SQL for updating an object of the given type. If a concrete bean is given,

+     * then a concrete update statement is created, otherwise an update statement usable in a

+     * prepared statement is build.

+     * 

+     * @param model       The database model

+     * @param dynaClass   The type

+     * @param primaryKeys The primary keys

+     * @param properties  The properties to write

+     * @param bean        Optionally the concrete bean to update

+     * @return The SQL required to update the instance

      */

-    public String getUpdateSql(Database model, DynaBean dynaBean)

+    protected String createUpdateSql(Database model, SqlDynaClass dynaClass, SqlDynaProperty[] primaryKeys, SqlDynaProperty[] properties, DynaBean oldBean, DynaBean newBean)

     {

-        SqlDynaClass      dynaClass   = model.getDynaClassFor(dynaBean);

-        SqlDynaProperty[] primaryKeys = dynaClass.getPrimaryKeyProperties();

+        Table   table           = model.findTable(dynaClass.getTableName());

+        HashMap oldColumnValues = toColumnValues(primaryKeys, oldBean);

+        HashMap newColumnValues = toColumnValues(properties, newBean);

 

         if (primaryKeys.length == 0)

         {

             _log.info("Cannot update instances of type " + dynaClass + " because it has no primary keys");

             return null;

         }

-

-        return createUpdateSql(model, dynaClass, primaryKeys, dynaClass.getNonPrimaryKeyProperties(), dynaBean);

+        else

+        {

+            return _builder.getUpdateSql(table, oldColumnValues, newColumnValues, newBean == null);

+        }

     }

 

     /**

      * {@inheritDoc}

      */

-    public void update(Connection connection, Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException

+    public String getUpdateSql(Database model, DynaBean dynaBean)

     {

-        SqlDynaClass      dynaClass   = model.getDynaClassFor(oldDynaBean);

-        SqlDynaProperty[] primaryKeys = dynaClass.getPrimaryKeyProperties();

+        SqlDynaClass      dynaClass      = model.getDynaClassFor(dynaBean);

+        SqlDynaProperty[] primaryKeys    = dynaClass.getPrimaryKeyProperties();

+        SqlDynaProperty[] nonPrimaryKeys = dynaClass.getNonPrimaryKeyProperties();

 

-        if (!dynaClass.getTable().equals(model.getDynaClassFor(newDynaBean)))

-        {

-            throw new DatabaseOperationException("The old and new dyna beans need to be for the same table");

-        }

         if (primaryKeys.length == 0)

         {

             _log.info("Cannot update instances of type " + dynaClass + " because it has no primary keys");

-            return;

+            return null;

         }

-

-        SqlDynaProperty[] properties = dynaClass.getSqlDynaProperties();

-        String            sql        = createUpdateSql(model, dynaClass, primaryKeys, properties, null);

-        PreparedStatement statement  = null;

-

-        if (_log.isDebugEnabled())

+        else

         {

-            _log.debug("About to execute SQL: " + sql);

-        }

-        try

-        {

-            beforeUpdate(connection, dynaClass.getTable());

-

-            statement = connection.prepareStatement(sql);

-

-            int sqlIndex = 1;

-

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

-            {

-                setObject(statement, sqlIndex++, newDynaBean, properties[idx]);

-            }

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

-            {

-                setObject(statement, sqlIndex++, oldDynaBean, primaryKeys[idx]);

-            }

-

-            int count = statement.executeUpdate();

-

-            afterUpdate(connection, dynaClass.getTable());

-

-            if (count != 1)

-            {

-                _log.warn("Attempted to insert a single row " + newDynaBean +

-                         " into table " + dynaClass.getTableName() +

-                         " but changed " + count + " row(s)");

-            }

-        }

-        catch (SQLException ex)

-        {

-            throw new DatabaseOperationException("Error while updating in the database", ex);

-        }

-        finally

-        {

-            closeStatement(statement);

+            return createUpdateSql(model, dynaClass, primaryKeys, nonPrimaryKeys, dynaBean);

         }

     }

 

     /**

      * {@inheritDoc}

      */

-    public void update(Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException

+    public String getUpdateSql(Database model, DynaBean oldDynaBean, DynaBean newDynaBean)

     {

-        Connection connection = borrowConnection();

+        SqlDynaClass      dynaClass      = model.getDynaClassFor(oldDynaBean);

+        SqlDynaProperty[] primaryKeys    = dynaClass.getPrimaryKeyProperties();

+        SqlDynaProperty[] nonPrimaryKeys = dynaClass.getNonPrimaryKeyProperties();

 

-        try

+        if (primaryKeys.length == 0)

         {

-            update(connection, model, oldDynaBean, newDynaBean);

+            _log.info("Cannot update instances of type " + dynaClass + " because it has no primary keys");

+            return null;

         }

-        finally

+        else

         {

-            returnConnection(connection);

+            return createUpdateSql(model, dynaClass, primaryKeys, nonPrimaryKeys, oldDynaBean, newDynaBean);

         }

     }

 

@@ -1774,6 +1745,87 @@
     }

 

     /**

+     * {@inheritDoc}

+     */

+    public void update(Connection connection, Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException

+    {

+        SqlDynaClass      dynaClass   = model.getDynaClassFor(oldDynaBean);

+        SqlDynaProperty[] primaryKeys = dynaClass.getPrimaryKeyProperties();

+

+        if (!dynaClass.getTable().equals(model.getDynaClassFor(newDynaBean).getTable()))

+        {

+            throw new DatabaseOperationException("The old and new dyna beans need to be for the same table");

+        }

+        if (primaryKeys.length == 0)

+        {

+            _log.info("Cannot update instances of type " + dynaClass + " because it has no primary keys");

+            return;

+        }

+

+        SqlDynaProperty[] properties = dynaClass.getSqlDynaProperties();

+        String            sql        = createUpdateSql(model, dynaClass, primaryKeys, properties, null, null);

+        PreparedStatement statement  = null;

+

+        if (_log.isDebugEnabled())

+        {

+            _log.debug("About to execute SQL: " + sql);

+        }

+        try

+        {

+            beforeUpdate(connection, dynaClass.getTable());

+

+            statement = connection.prepareStatement(sql);

+

+            int sqlIndex = 1;

+

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

+            {

+                setObject(statement, sqlIndex++, newDynaBean, properties[idx]);

+            }

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

+            {

+                setObject(statement, sqlIndex++, oldDynaBean, primaryKeys[idx]);

+            }

+

+            int count = statement.executeUpdate();

+

+            afterUpdate(connection, dynaClass.getTable());

+

+            if (count != 1)

+            {

+                _log.warn("Attempted to insert a single row " + newDynaBean +

+                         " into table " + dynaClass.getTableName() +

+                         " but changed " + count + " row(s)");

+            }

+        }

+        catch (SQLException ex)

+        {

+            throw new DatabaseOperationException("Error while updating in the database", ex);

+        }

+        finally

+        {

+            closeStatement(statement);

+        }

+    }

+

+    /**

+     * {@inheritDoc}

+     */

+    public void update(Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException

+    {

+        Connection connection = borrowConnection();

+

+        try

+        {

+            update(connection, model, oldDynaBean, newDynaBean);

+        }

+        finally

+        {

+            returnConnection(connection);

+        }

+    }

+

+    /**

      * Allows platforms to issue statements directly before rows are updated in

      * the specified table.

      *  

diff --git a/src/java/org/apache/ddlutils/platform/SqlBuilder.java b/src/java/org/apache/ddlutils/platform/SqlBuilder.java
index 6cb31fb..10d4dae 100644
--- a/src/java/org/apache/ddlutils/platform/SqlBuilder.java
+++ b/src/java/org/apache/ddlutils/platform/SqlBuilder.java
@@ -1526,7 +1526,61 @@
      */
     public String getUpdateSql(Table table, Map columnValues, boolean genPlaceholders)
     {
-        return getUpdateSql(table, columnValues, columnValues, genPlaceholders);
+        StringBuffer buffer = new StringBuffer("UPDATE ");
+        boolean      addSep = false;
+
+        buffer.append(getDelimitedIdentifier(getTableName(table)));
+        buffer.append(" SET ");
+
+        for (int idx = 0; idx < table.getColumnCount(); idx++)
+        {
+            Column column = table.getColumn(idx);
+
+            if (!column.isPrimaryKey() && columnValues.containsKey(column.getName()))
+            {
+                if (addSep)
+                {
+                    buffer.append(", ");
+                }
+                buffer.append(getDelimitedIdentifier(column.getName()));
+                buffer.append(" = ");
+                if (genPlaceholders)
+                {
+                    buffer.append("?");
+                }
+                else
+                {
+                    buffer.append(getValueAsString(column, columnValues.get(column.getName())));
+                }
+                addSep = true;
+            }
+        }
+        buffer.append(" WHERE ");
+        addSep = false;
+        for (int idx = 0; idx < table.getColumnCount(); idx++)
+        {
+            Column column = table.getColumn(idx);
+
+            if (column.isPrimaryKey() && columnValues.containsKey(column.getName()))
+            {
+                if (addSep)
+                {
+                    buffer.append(" AND ");
+                }
+                buffer.append(getDelimitedIdentifier(column.getName()));
+                buffer.append(" = ");
+                if (genPlaceholders)
+                {
+                    buffer.append("?");
+                }
+                else
+                {
+                    buffer.append(getValueAsString(column, columnValues.get(column.getName())));
+                }
+                addSep = true;
+            }
+        }
+        return buffer.toString();
     }
 
     /**
@@ -1536,9 +1590,7 @@
      * 
      * @param table           The table
      * @param oldColumnValues Contains the column values to identify the row to update 
-     * @param columnValues    Contains the values for the columns to update, and should also
-     *                        contain the primary key values to identify the object to update
-     *                        in case <code>genPlaceholders</code> is <code>false</code> 
+     * @param newColumnValues Contains the values for the columns to update 
      * @param genPlaceholders Whether to generate value placeholders for a
      *                        prepared statement (both for the pk values and the object values)
      * @return The update sql
@@ -1555,7 +1607,7 @@
         {
             Column column = table.getColumn(idx);
 
-            if (!column.isPrimaryKey() && newColumnValues.containsKey(column.getName()))
+            if (newColumnValues.containsKey(column.getName()))
             {
                 if (addSep)
                 {
@@ -1580,7 +1632,7 @@
         {
             Column column = table.getColumn(idx);
 
-            if (column.isPrimaryKey() && oldColumnValues.containsKey(column.getName()))
+            if (oldColumnValues.containsKey(column.getName()))
             {
                 if (addSep)
                 {
@@ -2599,6 +2651,9 @@
                 case CascadeActionEnum.VALUE_SET_NULL:
                     print("SET NULL");
                     break;
+                case CascadeActionEnum.VALUE_SET_DEFAULT:
+                    print("SET DEFAULT");
+                    break;
                 case CascadeActionEnum.VALUE_RESTRICT:
                     print("RESTRICT");
                     break;
@@ -2631,6 +2686,9 @@
                 case CascadeActionEnum.VALUE_SET_NULL:
                     print("SET NULL");
                     break;
+                case CascadeActionEnum.VALUE_SET_DEFAULT:
+                    print("SET DEFAULT");
+                    break;
                 case CascadeActionEnum.VALUE_RESTRICT:
                     print("RESTRICT");
                     break;
diff --git a/src/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java b/src/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java
index 5d26c7b..d0a162f 100644
--- a/src/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java
+++ b/src/java/org/apache/ddlutils/platform/derby/DerbyPlatform.java
@@ -51,7 +51,6 @@
     public DerbyPlatform()

     {

         super();

-        getPlatformInfo().setSetDefaultActionSupported(false);

         getPlatformInfo().addNativeTypeMapping(Types.DOUBLE, "DOUBLE");

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

         setSqlBuilder(new DerbyBuilder(this));

diff --git a/src/test/org/apache/ddlutils/io/TestConstraints.java b/src/test/org/apache/ddlutils/io/TestConstraints.java
index 85c334d..b294637 100644
--- a/src/test/org/apache/ddlutils/io/TestConstraints.java
+++ b/src/test/org/apache/ddlutils/io/TestConstraints.java
@@ -25,6 +25,7 @@
 import org.apache.commons.lang.StringUtils;

 import org.apache.ddlutils.DdlUtilsException;

 import org.apache.ddlutils.model.Database;

+import org.apache.ddlutils.platform.derby.DerbyPlatform;

 import org.apache.ddlutils.platform.sybase.SybasePlatform;

 

 import junit.framework.Test;

@@ -580,7 +581,7 @@
      */

     public void testForeignKeyWithOnDeleteSetDefault()

     {

-        if (getPlatformInfo().isSetDefaultActionSupported())

+        if (!DerbyPlatform.DATABASENAME.equals(getPlatform().getName()))

         {

             final String modelXml = 

                 "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+

@@ -590,7 +591,7 @@
                 "  </table>\n"+

                 "  <table name='roundtrip_2'>\n"+

                 "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+

-                "    <column name='avalue' type='INTEGER' required='false' default='0'/>\n"+

+                "    <column name='avalue' type='INTEGER' required='false' default='2'/>\n"+

                 "    <foreign-key foreignTable='roundtrip_1' onDelete='setdefault'>\n"+

                 "      <reference local='avalue' foreign='pk'/>\n"+

                 "    </foreign-key>\n"+

@@ -600,14 +601,16 @@
             performConstraintsTest(modelXml, true);

     

             insertRow("roundtrip_1", new Object[] { new Integer(1) });

+            insertRow("roundtrip_1", new Object[] { new Integer(2) });

             insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) });

     

             List beansTable1 = getRows("roundtrip_1");

             List beansTable2 = getRows("roundtrip_2");

     

-            assertEquals(1, beansTable1.size());

+            assertEquals(2, beansTable1.size());

             assertEquals(1, beansTable2.size());

             assertEquals(new Integer(1), beansTable1.get(0), "pk");

+            assertEquals(new Integer(2), beansTable1.get(1), "pk");

             assertEquals(new Integer(5), beansTable2.get(0), "pk");

             assertEquals(new Integer(1), beansTable2.get(0), "avalue");

     

@@ -616,10 +619,11 @@
             beansTable1 = getRows("roundtrip_1");

             beansTable2 = getRows("roundtrip_2");

     

-            assertEquals(0, beansTable1.size());

+            assertEquals(1, beansTable1.size());

             assertEquals(1, beansTable2.size());

+            assertEquals(new Integer(2), beansTable1.get(0), "pk");

             assertEquals(new Integer(5), beansTable2.get(0), "pk");

-            assertEquals(new Integer(0), beansTable2.get(0), "avalue");

+            assertEquals(new Integer(2), beansTable2.get(0), "avalue");

         }

     }

 

@@ -671,99 +675,7 @@
      */

     public void testForeignKeyWithOnUpdateCascade()

     {

-        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='INTEGER' primaryKey='true' required='true'/>\n"+

-            "  </table>\n"+

-            "  <table name='roundtrip_2'>\n"+

-            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+

-            "    <column name='avalue' type='INTEGER' required='true'/>\n"+

-            "    <foreign-key foreignTable='roundtrip_1' onUpdate='cascade'>\n"+

-            "      <reference local='avalue' foreign='pk'/>\n"+

-            "    </foreign-key>\n"+

-            "  </table>\n"+

-            "</database>";

-

-        performConstraintsTest(modelXml, true);

-

-        insertRow("roundtrip_1", new Object[] { new Integer(1) });

-        insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) });

-

-        List beansTable1 = getRows("roundtrip_1");

-        List beansTable2 = getRows("roundtrip_2");

-

-        assertEquals(1, beansTable1.size());

-        assertEquals(1, beansTable2.size());

-        assertEquals(new Integer(1), beansTable1.get(0), "pk");

-        assertEquals(new Integer(5), beansTable2.get(0), "pk");

-        assertEquals(new Integer(1), beansTable2.get(0), "avalue");

-

-        updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(2) });

-

-        beansTable1 = getRows("roundtrip_1");

-        beansTable2 = getRows("roundtrip_2");

-

-        assertEquals(1, beansTable1.size());

-        assertEquals(1, beansTable2.size());

-        assertEquals(new Integer(2), beansTable1.get(0), "pk");

-        assertEquals(new Integer(5), beansTable2.get(0), "pk");

-        assertEquals(new Integer(2), beansTable2.get(0), "avalue");

-    }

-

-    /**

-     * Tests two tables with a foreign key with a set-null onUpdate action. 

-     */

-    public void testForeignKeyWithOnUpdateSetNull()

-    {

-        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='INTEGER' primaryKey='true' required='true'/>\n"+

-            "  </table>\n"+

-            "  <table name='roundtrip_2'>\n"+

-            "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+

-            "    <column name='avalue' type='INTEGER' required='false'/>\n"+

-            "    <foreign-key foreignTable='roundtrip_1' onUpdate='setnull'>\n"+

-            "      <reference local='avalue' foreign='pk'/>\n"+

-            "    </foreign-key>\n"+

-            "  </table>\n"+

-            "</database>";

-

-        performConstraintsTest(modelXml, true);

-

-        insertRow("roundtrip_1", new Object[] { new Integer(1) });

-        insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) });

-

-        List beansTable1 = getRows("roundtrip_1");

-        List beansTable2 = getRows("roundtrip_2");

-

-        assertEquals(1, beansTable1.size());

-        assertEquals(1, beansTable2.size());

-        assertEquals(new Integer(1), beansTable1.get(0), "pk");

-        assertEquals(new Integer(5), beansTable2.get(0), "pk");

-        assertEquals(new Integer(1), beansTable2.get(0), "avalue");

-

-        updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(2) });

-

-        beansTable1 = getRows("roundtrip_1");

-        beansTable2 = getRows("roundtrip_2");

-

-        assertEquals(1, beansTable1.size());

-        assertEquals(1, beansTable2.size());

-        assertEquals(new Integer(2), beansTable1.get(0), "pk");

-        assertEquals(new Integer(5), beansTable2.get(0), "pk");

-        assertEquals((Object)null, beansTable2.get(0), "avalue");

-    }

-

-    /**

-     * Tests two tables with a foreign key with a det-default onUpdate action. 

-     */

-    public void testForeignKeyWithOnUpdateSetDefault()

-    {

-        if (getPlatformInfo().isSetDefaultActionSupported())

+        if (!DerbyPlatform.DATABASENAME.equals(getPlatform().getName()))

         {

             final String modelXml = 

                 "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+

@@ -773,7 +685,105 @@
                 "  </table>\n"+

                 "  <table name='roundtrip_2'>\n"+

                 "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+

-                "    <column name='avalue' type='INTEGER' required='false' default='2'/>\n"+

+                "    <column name='avalue' type='INTEGER' required='true'/>\n"+

+                "    <foreign-key foreignTable='roundtrip_1' onUpdate='cascade'>\n"+

+                "      <reference local='avalue' foreign='pk'/>\n"+

+                "    </foreign-key>\n"+

+                "  </table>\n"+

+                "</database>";

+    

+            performConstraintsTest(modelXml, true);

+    

+            insertRow("roundtrip_1", new Object[] { new Integer(1) });

+            insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) });

+    

+            List beansTable1 = getRows("roundtrip_1");

+            List beansTable2 = getRows("roundtrip_2");

+    

+            assertEquals(1, beansTable1.size());

+            assertEquals(1, beansTable2.size());

+            assertEquals(new Integer(1), beansTable1.get(0), "pk");

+            assertEquals(new Integer(5), beansTable2.get(0), "pk");

+            assertEquals(new Integer(1), beansTable2.get(0), "avalue");

+    

+            updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(2) });

+    

+            beansTable1 = getRows("roundtrip_1");

+            beansTable2 = getRows("roundtrip_2");

+    

+            assertEquals(1, beansTable1.size());

+            assertEquals(1, beansTable2.size());

+            assertEquals(new Integer(2), beansTable1.get(0), "pk");

+            assertEquals(new Integer(5), beansTable2.get(0), "pk");

+            assertEquals(new Integer(2), beansTable2.get(0), "avalue");

+        }

+    }

+

+    /**

+     * Tests two tables with a foreign key with a set-null onUpdate action. 

+     */

+    public void testForeignKeyWithOnUpdateSetNull()

+    {

+        if (!DerbyPlatform.DATABASENAME.equals(getPlatform().getName()))

+        {

+            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='INTEGER' primaryKey='true' required='true'/>\n"+

+                "  </table>\n"+

+                "  <table name='roundtrip_2'>\n"+

+                "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+

+                "    <column name='avalue' type='INTEGER' required='false'/>\n"+

+                "    <foreign-key foreignTable='roundtrip_1' onUpdate='setnull'>\n"+

+                "      <reference local='avalue' foreign='pk'/>\n"+

+                "    </foreign-key>\n"+

+                "  </table>\n"+

+                "</database>";

+    

+            performConstraintsTest(modelXml, true);

+    

+            insertRow("roundtrip_1", new Object[] { new Integer(1) });

+            insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) });

+    

+            List beansTable1 = getRows("roundtrip_1");

+            List beansTable2 = getRows("roundtrip_2");

+    

+            assertEquals(1, beansTable1.size());

+            assertEquals(1, beansTable2.size());

+            assertEquals(new Integer(1), beansTable1.get(0), "pk");

+            assertEquals(new Integer(5), beansTable2.get(0), "pk");

+            assertEquals(new Integer(1), beansTable2.get(0), "avalue");

+    

+            updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(2) });

+    

+            beansTable1 = getRows("roundtrip_1");

+            beansTable2 = getRows("roundtrip_2");

+    

+            assertEquals(1, beansTable1.size());

+            assertEquals(1, beansTable2.size());

+            assertEquals(new Integer(2), beansTable1.get(0), "pk");

+            assertEquals(new Integer(5), beansTable2.get(0), "pk");

+            assertEquals((Object)null, beansTable2.get(0), "avalue");

+        }

+    }

+

+    /**

+     * Tests two tables with a foreign key with a det-default onUpdate action. 

+     */

+    public void testForeignKeyWithOnUpdateSetDefault()

+    {

+        if (!DerbyPlatform.DATABASENAME.equals(getPlatform().getName()))

+        {

+            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='INTEGER' primaryKey='true' required='true'/>\n"+

+                "  </table>\n"+

+                "  <table name='roundtrip_2'>\n"+

+                "    <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+

+                "    <column name='avalue' type='INTEGER' required='false' default='1'/>\n"+

                 "    <foreign-key foreignTable='roundtrip_1' onUpdate='setdefault'>\n"+

                 "      <reference local='avalue' foreign='pk'/>\n"+

                 "    </foreign-key>\n"+

@@ -784,7 +794,7 @@
     

             insertRow("roundtrip_1", new Object[] { new Integer(1) });

             insertRow("roundtrip_1", new Object[] { new Integer(2) });

-            insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) });

+            insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(2) });

     

             List beansTable1 = getRows("roundtrip_1");

             List beansTable2 = getRows("roundtrip_2");

@@ -794,19 +804,19 @@
             assertEquals(new Integer(1), beansTable1.get(0), "pk");

             assertEquals(new Integer(2), beansTable1.get(1), "pk");

             assertEquals(new Integer(5), beansTable2.get(0), "pk");

-            assertEquals(new Integer(1), beansTable2.get(0), "avalue");

+            assertEquals(new Integer(2), beansTable2.get(0), "avalue");

     

-            updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(0) });

+            updateRow("roundtrip_1", (DynaBean)beansTable1.get(1), new Object[] { new Integer(0) });

     

             beansTable1 = getRows("roundtrip_1");

             beansTable2 = getRows("roundtrip_2");

     

             assertEquals(2, beansTable1.size());

             assertEquals(1, beansTable2.size());

-            assertEquals(new Integer(0), beansTable1.get(0), "pk");

-            assertEquals(new Integer(2), beansTable1.get(1), "pk");

+            assertEquals(new Integer(1), beansTable1.get(0), "pk");

+            assertEquals(new Integer(0), beansTable1.get(1), "pk");

             assertEquals(new Integer(5), beansTable2.get(0), "pk");

-            assertEquals(new Integer(2), beansTable2.get(0), "avalue");

+            assertEquals(new Integer(1), beansTable2.get(0), "avalue");

         }

     }

 }

diff --git a/src/test/org/apache/ddlutils/platform/TestSqlBuilder.java b/src/test/org/apache/ddlutils/platform/TestSqlBuilder.java
index afe1bd8..b51a3e6 100644
--- a/src/test/org/apache/ddlutils/platform/TestSqlBuilder.java
+++ b/src/test/org/apache/ddlutils/platform/TestSqlBuilder.java
@@ -36,7 +36,7 @@
     /**

      * Tests the {@link SqlBuilder#getUpdateSql(Table, Map, boolean)} method.

      */

-    public void testUpdateSql()

+    public void testUpdateSql1()

     {

         final String modelXml =

             "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+

@@ -62,4 +62,37 @@
         assertEquals("UPDATE \"TestTable\" SET \"name\" = 'ddlutils' WHERE \"id\" = '0'",

                      sql);

     }

+

+    /**

+     * Tests the {@link SqlBuilder#getUpdateSql(Table, Map, Map, boolean)} method.

+     */

+    public void testUpdateSql2()

+    {

+        final String modelXml =

+            "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+

+            "<database name='ddlutils'>\n"+

+            "  <table name='TestTable'>\n"+

+            "    <column name='id' autoIncrement='true' type='INTEGER' primaryKey='true'/>\n"+

+            "    <column name='name' type='VARCHAR' size='15'/>\n"+

+            "  </table>\n"+

+            "</database>";

+

+        TestPlatform platform   = new TestPlatform();

+        SqlBuilder   sqlBuilder = platform.getSqlBuilder();

+        Database     database   = parseDatabaseFromString(modelXml);

+        Map          oldMap     = new HashMap();

+        Map          newMap     = new HashMap();

+

+        oldMap.put("id", new Integer(0));

+

+        newMap.put("name", "ddlutils");

+        newMap.put("id", new Integer(1));

+

+        platform.setDelimitedIdentifierModeOn(true);

+        

+        String sql = sqlBuilder.getUpdateSql(database.getTable(0), oldMap, newMap, false);

+

+        assertEquals("UPDATE \"TestTable\" SET \"id\" = '1', \"name\" = 'ddlutils' WHERE \"id\" = '0'",

+                     sql);

+    }

 }