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

svn commit: r358148 - in /db/ddlutils/trunk/src/java/org/apache/ddlutils/platform: DefaultValueHelper.java DerbyBuilder.java PlatformImplBase.java SqlBuilder.java

Author: tomdz
Date: Tue Dec 20 15:46:57 2005
New Revision: 358148

URL: http://svn.apache.org/viewcvs?rev=358148&view=rev
Log:
Added ability for the sql builders to convert the default values to the corresponding native values
Added first usage of this to the Derby builder for column types BOOLEAN/BIT (which are mapped to SMALLINT)

Added:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DefaultValueHelper.java
Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyBuilder.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DefaultValueHelper.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DefaultValueHelper.java?rev=358148&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DefaultValueHelper.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DefaultValueHelper.java Tue Dec 20 15:46:57 2005
@@ -0,0 +1,86 @@
+package org.apache.ddlutils.platform;
+
+import java.sql.Types;
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.ConvertUtils;
+import org.apache.ddlutils.model.TypeMap;
+import org.apache.ddlutils.util.Jdbc3Utils;
+
+/**
+ * Helper class for dealing with default values, e.g. converting them to other types.
+ * 
+ * @author Thomas Dudziak
+ * @version $Revision: 289996 $
+ */
+public class DefaultValueHelper
+{
+    /**
+     * Converts the given default value from the specified original to the target
+     * jdbc type.
+     * 
+     * @param defaultValue     The default value
+     * @param originalTypeCode The original type code
+     * @param targetTypeCode   The target type code
+     * @return The converted default value 
+     */
+    public Object convert(String defaultValue, int originalTypeCode, int targetTypeCode)
+    {
+        Object result = defaultValue;
+
+        if (defaultValue != null)
+        {
+            switch (originalTypeCode)
+            {
+                case Types.BIT:
+                    result = convertBoolean(defaultValue, targetTypeCode);
+                    break;
+                default:
+                    if (Jdbc3Utils.supportsJava14JdbcTypes() &&
+                        (originalTypeCode == Jdbc3Utils.determineBooleanTypeCode()))
+                    {
+                        result = convertBoolean(defaultValue, targetTypeCode);
+                    }
+                    break;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a boolean default value to the given target type.
+     * 
+     * @param defaultValue   The default value
+     * @param targetTypeCode The target type code
+     * @return
+     */
+    private Object convertBoolean(String defaultValue, int targetTypeCode)
+    {
+        Boolean value  = null;
+        Object  result = null;
+
+        try
+        {
+            value = (Boolean)ConvertUtils.convert(defaultValue, Boolean.class);
+        }
+        catch (ConversionException ex)
+        {
+            return defaultValue;
+        }
+        
+        if ((targetTypeCode == Types.BIT) ||
+            (Jdbc3Utils.supportsJava14JdbcTypes() && (targetTypeCode == Jdbc3Utils.determineBooleanTypeCode())))
+        {
+            result = value;
+        }
+        else if (TypeMap.isNumericType(targetTypeCode))
+        {
+            result = (value.booleanValue() ? new Integer(1) : new Integer(0));
+        }
+        else
+        {
+            result = value.toString();
+        }
+        return result;
+    }
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyBuilder.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyBuilder.java?rev=358148&r1=358147&r2=358148&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyBuilder.java Tue Dec 20 15:46:57 2005
@@ -17,10 +17,12 @@
  */
 
 import java.io.IOException;
+import java.sql.Types;
 
 import org.apache.ddlutils.PlatformInfo;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.util.Jdbc3Utils;
 
 /**
  * The SQL Builder for Derby.
@@ -38,6 +40,22 @@
     public DerbyBuilder(PlatformInfo info)
     {
         super(info);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected String getNativeDefaultValue(Column column)
+    {
+        if ((column.getTypeCode() == Types.BIT) ||
+            (Jdbc3Utils.supportsJava14JdbcTypes() && (column.getTypeCode() == Jdbc3Utils.determineBooleanTypeCode())))
+        {
+            return getDefaultValueHelper().convert(column.getDefaultValue(), column.getTypeCode(), Types.SMALLINT).toString();
+        }
+        else
+        {
+            return super.getNativeDefaultValue(column);
+        }
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java?rev=358148&r1=358147&r2=358148&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java Tue Dec 20 15:46:57 2005
@@ -26,6 +26,7 @@
 import java.sql.SQLWarning;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -35,6 +36,8 @@
 
 import org.apache.commons.beanutils.DynaBean;
 import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.Predicate;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ddlutils.DynaSqlException;
@@ -826,51 +829,54 @@
     }
 
     /**
-     * {@inheritDoc}
+     * Returns all properties where the column is not non-autoincrement and for which the bean
+     * either has a value or the column hasn't got a default value, for the given dyna class.
+     * 
+     * @param model     The database model
+     * @param dynaClass The dyna class
+     * @param bean      The bean
+     * @return The properties
      */
-    public void insert(Connection connection, Database model, DynaBean dynaBean) throws DynaSqlException
+    private SqlDynaProperty[] getPropertiesForInsertion(Database model, SqlDynaClass dynaClass, final DynaBean bean)
     {
-        SqlDynaClass      dynaClass  = model.getDynaClassFor(dynaBean);
         SqlDynaProperty[] properties = dynaClass.getSqlDynaProperties();
 
-        if (properties.length == 0)
-        {
-            _log.warn("Cannot insert instances of type " + dynaClass + " because it has no properties");
-            return;
-        }
+        Collection result = CollectionUtils.select(Arrays.asList(properties), new Predicate() {
+            public boolean evaluate(Object input) {
+                SqlDynaProperty prop = (SqlDynaProperty)input;
 
-        Column[] columns = model.findTable(dynaClass.getTableName()).getAutoIncrementColumns();
+                return !prop.getColumn().isAutoIncrement() &&
+                       ((bean.get(prop.getName()) != null) || (prop.getColumn().getDefaultValue() == null));
+            }
+        });
 
-        if (columns.length > 0)
-        {
-            SqlDynaProperty[] newProperties = new SqlDynaProperty[properties.length - 1];
-            int               newIdx        = 0;
+        return (SqlDynaProperty[])result.toArray(new SqlDynaProperty[result.size()]);
+    }
 
-            // We have to remove the auto-increment columns as some databases won't like
-            // it being present in the insert command
+    /**
+     * {@inheritDoc}
+     */
+    public void insert(Connection connection, Database model, DynaBean dynaBean) throws DynaSqlException
+    {
+        SqlDynaClass      dynaClass       = model.getDynaClassFor(dynaBean);
+        SqlDynaProperty[] properties      = getPropertiesForInsertion(model, dynaClass, dynaBean);
+        Column[]          autoIncrColumns = model.findTable(dynaClass.getTableName()).getAutoIncrementColumns();
 
-            for (int propIdx = 0; propIdx < properties.length; propIdx++)
-            {
-                for (int autoIncrColumnIdx = 0; autoIncrColumnIdx < columns.length; autoIncrColumnIdx++)
-                {
-                    if (properties[propIdx].getColumn() != columns[autoIncrColumnIdx])
-                    {
-                        newProperties[newIdx++] = properties[propIdx];
-                    }
-                }
-            }
-            properties = newProperties;
+        if ((properties.length == 0) && (autoIncrColumns.length == 0))
+        {
+            _log.warn("Cannot insert instances of type " + dynaClass + " because it has no usable properties");
+            return;
         }
-        
-        String            insertSql    = createInsertSql(model, dynaClass, properties, null);
-        String            queryIdSql   = columns.length > 0 ? createSelectLastInsertIdSql(model, dynaClass) : null;
-        PreparedStatement statement    = null;
+
+        String            insertSql  = createInsertSql(model, dynaClass, properties, null);
+        String            queryIdSql = autoIncrColumns.length > 0 ? createSelectLastInsertIdSql(model, dynaClass) : null;
+        PreparedStatement statement  = null;
 
         if (_log.isDebugEnabled())
         {
             _log.debug("About to execute SQL: " + insertSql);
         }
-        if ((columns.length > 0) && (queryIdSql == null))
+        if ((autoIncrColumns.length > 0) && (queryIdSql == null))
         {
             _log.warn("The database does not support querying for auto-generated pk values");
         }
@@ -921,11 +927,11 @@
 
                 lastInsertedIds.next();
 
-                for (int idx = 0; idx < columns.length; idx++)
+                for (int idx = 0; idx < autoIncrColumns.length; idx++)
                 {
-                    Object value = lastInsertedIds.getObject(columns[idx].getName());
+                    Object value = lastInsertedIds.getObject(autoIncrColumns[idx].getName());
     
-                    PropertyUtils.setProperty(dynaBean, columns[idx].getName(), value);
+                    PropertyUtils.setProperty(dynaBean, autoIncrColumns[idx].getName(), value);
                 }
             }
             catch (NoSuchMethodException ex)
@@ -1003,36 +1009,13 @@
                 }
 
                 dynaClass  = curDynaClass;
-                properties = dynaClass.getSqlDynaProperties();
+                properties = getPropertiesForInsertion(model, curDynaClass, dynaBean);
     
                 if (properties.length == 0)
                 {
-                    _log.warn("Cannot insert instances of type " + dynaClass + " because it has no properties");
+                    _log.warn("Cannot insert instances of type " + dynaClass + " because it has no usable properties");
                     continue;
                 }
-    
-                Column[] columns = model.findTable(dynaClass.getTableName()).getAutoIncrementColumns();
-    
-                if (columns.length > 0)
-                {
-                    SqlDynaProperty[] newProperties = new SqlDynaProperty[properties.length - 1];
-                    int               newIdx        = 0;
-    
-                    // We have to remove the auto-increment columns as some databases won't like
-                    // it being present in the insert command
-    
-                    for (int propIdx = 0; propIdx < properties.length; propIdx++)
-                    {
-                        for (int autoIncrColumnIdx = 0; autoIncrColumnIdx < columns.length; autoIncrColumnIdx++)
-                        {
-                            if (properties[propIdx].getColumn() != columns[autoIncrColumnIdx])
-                            {
-                                newProperties[newIdx++] = properties[propIdx];
-                            }
-                        }
-                    }
-                    properties = newProperties;
-                }
 
                 String insertSql = createInsertSql(model, dynaClass, properties, null);
 
@@ -1451,8 +1434,8 @@
      */
     protected void setObject(PreparedStatement statement, int sqlIndex, DynaBean dynaBean, SqlDynaProperty property) throws SQLException
     {
-        int    typeCode = property.getColumn().getTypeCode();
-        Object value    = dynaBean.get(property.getName());
+        int     typeCode = property.getColumn().getTypeCode();
+        Object  value    = dynaBean.get(property.getName());
 
         if (value == null)
         {

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java?rev=358148&r1=358147&r2=358148&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java Tue Dec 20 15:46:57 2005
@@ -35,6 +35,7 @@
 import org.apache.ddlutils.model.Index;
 import org.apache.ddlutils.model.IndexColumn;
 import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.model.TypeMap;
 
 /**
  * This class is a collection of Strategy methods for creating the DDL required to create and drop 
@@ -83,6 +84,9 @@
     /** The number formatter. */
     private NumberFormat _valueNumberFormat;
 
+    /** Helper object for dealing with default values. */
+    private DefaultValueHelper _defaultValueHelper = new DefaultValueHelper();
+
     //
     // Configuration
     //                
@@ -127,6 +131,16 @@
         _writer = writer;
     }
 
+    /**
+     * Returns the default value helper.
+     *
+     * @return The default value helper
+     */
+    protected DefaultValueHelper getDefaultValueHelper()
+    {
+        return _defaultValueHelper;
+    }
+
     /** 
      * Returns the string used to indent the SQL.
      * 
@@ -881,6 +895,77 @@
     }
 
     /**
+     * Generates the string representation of the given value.
+     * 
+     * @param column The column
+     * @param value  The value
+     * @return The string representation
+     */
+    protected String getValueAsString(Column column, Object value)
+    {
+        if (value == null)
+        {
+            return "NULL";
+        }
+
+        StringBuffer result = new StringBuffer();
+
+        // TODO: Handle binary types (BINARY, VARBINARY, LONGVARBINARY, BLOB)
+        switch (column.getTypeCode())
+        {
+            // Note: TIMESTAMP (java.sql.Timestamp) is properly handled by its toString method
+            case Types.DATE:
+                result.append(getPlatformInfo().getValueQuoteToken());
+                if (!(value instanceof String) && (_valueDateFormat != null))
+                {
+                    // TODO: Can the format method handle java.sql.Date properly ?
+                    result.append(_valueDateFormat.format(value));
+                }
+                else
+                {
+                    result.append(value.toString());
+                }
+                result.append(getPlatformInfo().getValueQuoteToken());
+                break;
+            case Types.TIME:
+                result.append(getPlatformInfo().getValueQuoteToken());
+                if (!(value instanceof String) && (_valueTimeFormat != null))
+                {
+                    // TODO: Can the format method handle java.sql.Date properly ?
+                    result.append(_valueTimeFormat.format(value));
+                }
+                else
+                {
+                    result.append(value.toString());
+                }
+                result.append(getPlatformInfo().getValueQuoteToken());
+                break;
+            case Types.REAL:
+            case Types.NUMERIC:
+            case Types.FLOAT:
+            case Types.DOUBLE:
+            case Types.DECIMAL:
+                result.append(getPlatformInfo().getValueQuoteToken());
+                if (!(value instanceof String) && (_valueNumberFormat != null))
+                {
+                    result.append(_valueNumberFormat.format(value));
+                }
+                else
+                {
+                    result.append(value.toString());
+                }
+                result.append(getPlatformInfo().getValueQuoteToken());
+                break;
+            default:
+                result.append(getPlatformInfo().getValueQuoteToken());
+                result.append(value.toString());
+                result.append(getPlatformInfo().getValueQuoteToken());
+                break;
+        }
+        return result.toString();
+    }
+
+    /**
      * Generates the SQL for querying the id that was created in the last insertion
      * operation. This is obviously only useful for pk fields that are auto-incrementing.
      * A database that does not support this, will return <code>null</code>.
@@ -1028,9 +1113,7 @@
         if (column.getDefaultValue() != null)
         {
             print(" DEFAULT ");
-            print(getPlatformInfo().getValueQuoteToken());
-            print(column.getDefaultValue());
-            print(getPlatformInfo().getValueQuoteToken());
+            writeColumnDefaultValue(table, column);
         }
         if (column.isRequired())
         {
@@ -1124,76 +1207,37 @@
     }
 
     /**
-     * Generates the string representation of the given value.
+     * Returns the native default value for the column.
      * 
      * @param column The column
-     * @param value  The value
-     * @return The string representation
+     * @return The native default value
      */
-    protected String getValueAsString(Column column, Object value)
+    protected String getNativeDefaultValue(Column column)
     {
-        if (value == null)
+        return column.getDefaultValue();
+    }
+    
+    /**
+     * Prints the default value of the column.
+     * 
+     * @param table  The table
+     * @param column The column
+     */ 
+    protected void writeColumnDefaultValue(Table table, Column column) throws IOException
+    {
+        boolean shouldUseQuotes = !TypeMap.isNumericType(column.getTypeCode());
+
+        if (shouldUseQuotes)
         {
-            return "NULL";
+            print(getPlatformInfo().getValueQuoteToken());
         }
-
-        StringBuffer result = new StringBuffer();
-
-        // TODO: Handle binary types (BINARY, VARBINARY, LONGVARBINARY, BLOB)
-        switch (column.getTypeCode())
+        print(getNativeDefaultValue(column).toString());
+        if (shouldUseQuotes)
         {
-            // Note: TIMESTAMP (java.sql.Timestamp) is properly handled by its toString method
-            case Types.DATE:
-                result.append(getPlatformInfo().getValueQuoteToken());
-                if (!(value instanceof String) && (_valueDateFormat != null))
-                {
-                    // TODO: Can the format method handle java.sql.Date properly ?
-                    result.append(_valueDateFormat.format(value));
-                }
-                else
-                {
-                    result.append(value.toString());
-                }
-                result.append(getPlatformInfo().getValueQuoteToken());
-                break;
-            case Types.TIME:
-                result.append(getPlatformInfo().getValueQuoteToken());
-                if (!(value instanceof String) && (_valueTimeFormat != null))
-                {
-                    // TODO: Can the format method handle java.sql.Date properly ?
-                    result.append(_valueTimeFormat.format(value));
-                }
-                else
-                {
-                    result.append(value.toString());
-                }
-                result.append(getPlatformInfo().getValueQuoteToken());
-                break;
-            case Types.REAL:
-            case Types.NUMERIC:
-            case Types.FLOAT:
-            case Types.DOUBLE:
-            case Types.DECIMAL:
-                result.append(getPlatformInfo().getValueQuoteToken());
-                if (!(value instanceof String) && (_valueNumberFormat != null))
-                {
-                    result.append(_valueNumberFormat.format(value));
-                }
-                else
-                {
-                    result.append(value.toString());
-                }
-                result.append(getPlatformInfo().getValueQuoteToken());
-                break;
-            default:
-                result.append(getPlatformInfo().getValueQuoteToken());
-                result.append(value.toString());
-                result.append(getPlatformInfo().getValueQuoteToken());
-                break;
+            print(getPlatformInfo().getValueQuoteToken());
         }
-        return result.toString();
     }
-    
+
     /**
      * Prints that the column is an auto increment column.
      *