Author: tomdz
Date: Sun Jun 18 02:06:16 2006
New Revision: 415112

URL: http://svn.apache.org/viewvc?rev=415112&view=rev
Log:
Added generic method for unescaping special characters in the default value
Improved auto-increment handling

Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java
    
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java?rev=415112&r1=415111&r2=415112&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java Sun Jun 18 
02:06:16 2006
@@ -74,15 +74,11 @@
 
     /** Whether the database returns a synthetic default value for 
non-identity required columns. */ 
     private boolean _syntheticDefaultValueForRequiredReturned = false;
-    
-    /** Whether the platform allows for the explicit specification of values 
for identity columns in INSERT
-        and UPDATE statements. */ 
-    private boolean _identityOverrideAllowed = true;
 
     /** Whether the platform is able to determine auto increment status from 
an existing database. */ 
     private boolean _identityStatusReadingSupported = true;
 
-    // other ddl properties
+    // other DDL/DML properties
 
     /** Whether comments are supported. */
     private boolean _sqlCommentsSupported = true;
@@ -93,6 +89,17 @@
     /** Whether an ALTER TABLE is needed to drop indexes. */
     private boolean _alterTableForDropUsed = false;
 
+    /** Whether the platform allows for the explicit specification of values 
for identity columns in INSERT
+        and UPDATE statements. */ 
+    private boolean _identityOverrideAllowed = true;
+
+    /** Whether the values of identity columns can be read back from the 
database after insertion. */ 
+    private boolean _lastIdentityValueReadable = true;
+
+    /** Whether auto-commit mode for the reading of the values of identity 
columns after insertion
+        shall be used. */ 
+    private boolean _autoCommitModeForLastIdentityValueReading = true;
+
     /** Specifies the maximum length that an identifier (name of a table, 
column, constraint etc.)
         can have for this database; use -1 if there is no limit. */
     private int _maxIdentifierLength = -1;
@@ -401,28 +408,6 @@
     }
 
     /**
-     * Determines whether the platform is allows the explicit specification of 
values for
-     * identity columns in INSERT/UPDATE statements.
-     * 
-     * @return <code>true</code> if values for identity columns can be 
specified
-     */
-    public boolean isIdentityOverrideAllowed()
-    {
-        return _identityOverrideAllowed;
-    }
-
-    /**
-     * Specifies whether the platform is allows the explicit specification of 
values for
-     * identity columns in INSERT/UPDATE statements.
-     * 
-     * @param identityOverrideAllowed <code>true</code> if values for identity 
columns can be specified
-     */
-    public void setIdentityOverrideAllowed(boolean identityOverrideAllowed)
-    {
-        _identityOverrideAllowed = identityOverrideAllowed;
-    }
-
-    /**
      * Determines whether the platform is able to read the auto-increment 
status for columns
      * from an existing database.
      * 
@@ -508,6 +493,75 @@
     public void setAlterTableForDropUsed(boolean useAlterTableForDrop)
     {
         _alterTableForDropUsed = useAlterTableForDrop;
+    }
+
+    /**
+     * Determines whether the platform is allows the explicit specification of 
values for
+     * identity columns in INSERT/UPDATE statements.
+     * 
+     * @return <code>true</code> if values for identity columns can be 
specified
+     */
+    public boolean isIdentityOverrideAllowed()
+    {
+        return _identityOverrideAllowed;
+    }
+
+    /**
+     * Specifies whether the platform is allows the explicit specification of 
values for
+     * identity columns in INSERT/UPDATE statements.
+     * 
+     * @param identityOverrideAllowed <code>true</code> if values for identity 
columns can be specified
+     */
+    public void setIdentityOverrideAllowed(boolean identityOverrideAllowed)
+    {
+        _identityOverrideAllowed = identityOverrideAllowed;
+    }
+
+    /**
+     * Determines whether the values of identity columns can be read back from 
the
+     * database after insertion of a row.
+     * 
+     * @return <code>true</code> if the identity column(s) can be read back
+     */
+    public boolean isLastIdentityValueReadable()
+    {
+        return _lastIdentityValueReadable;
+    }
+
+    /**
+     * Specifies whether the values of identity columns can be read back from 
the
+     * database after insertion of a row.
+     * 
+     * @param lastIdentityValueReadable <code>true</code> if the identity 
column(s) can be read back
+     */
+    public void setLastIdentityValueReadable(boolean lastIdentityValueReadable)
+    {
+        _lastIdentityValueReadable = lastIdentityValueReadable;
+    }
+
+    /**
+     * Determines whether auto-commit mode for the reading of the values of 
identity columns
+     * after insertion shall be used, i.e. whether between the insertion of 
the row and the
+     * reading of the database-generated identity value a commit is issued.
+     * 
+     * @return <code>true</code> if auto-commit mode is used
+     */
+    public boolean isAutoCommitModeForLastIdentityValueReading()
+    {
+        return _autoCommitModeForLastIdentityValueReading;
+    }
+
+    /**
+     * Determines whether auto-commit mode for the reading of the values of 
identity columns
+     * after insertion shall be used, i.e. whether between the insertion of 
the row and the
+     * reading of the database-generated identity value a commit is issued.
+     * 
+     * @param autoCommitModeForLastIdentityValueReading <code>true</code> if 
auto-commit mode
+     *                                                  shall be used
+     */
+    public void setAutoCommitModeForLastIdentityValueReading(boolean 
autoCommitModeForLastIdentityValueReading)
+    {
+        _autoCommitModeForLastIdentityValueReading = 
autoCommitModeForLastIdentityValueReading;
     }
 
     /**

Modified: 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java?rev=415112&r1=415111&r2=415112&view=diff
==============================================================================
--- 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java 
(original)
+++ 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java 
Sun Jun 18 02:06:16 2006
@@ -31,6 +31,7 @@
 import java.util.Map;
 
 import org.apache.commons.collections.map.ListOrderedMap;
+import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ddlutils.Platform;
@@ -1042,5 +1043,37 @@
                 stmt.close();
             }
         }
+    }
+
+    /**
+     * Replaces a specific character sequence in the given text with the 
character sequence
+     * whose escaped version it is.
+     * 
+     * @param text      The text
+     * @param unescaped The unescaped string, e.g. "'"
+     * @param escaped   The escaped version, e.g. "''"
+     * @return The resulting text
+     */
+    protected String unescape(String text, String unescaped, String escaped)
+    {
+        String result = text;
+
+        // we need special handling if the single quote is escaped via a 
double single quote
+        if (escaped.equals("''"))
+        {
+            if ((result.length() >= 2) && result.startsWith("'") && 
result.endsWith("'"))
+            {
+                result = "'" + StringUtils.replace(result.substring(1, 
result.length() - 1), escaped, unescaped) + "'";
+            }
+            else
+            {
+                result = StringUtils.replace(result, escaped, unescaped);
+            }
+        }
+        else
+        {
+            result = StringUtils.replace(result, escaped, unescaped);
+        }
+        return result;
     }
 }

Modified: 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java?rev=415112&r1=415111&r2=415112&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 
Sun Jun 18 02:06:16 2006
@@ -1030,7 +1030,7 @@
     {
         Table table = model.findTable(dynaClass.getTableName());
 
-        return _builder.getSelectLastInsertId(table);
+        return _builder.getSelectLastIdentityValues(table);
     }
 
     /**
@@ -1138,21 +1138,37 @@
             return;
         }
 
-        String            insertSql  = createInsertSql(model, dynaClass, 
properties, null);
-        String            queryIdSql = autoIncrColumns.length > 0 ? 
createSelectLastInsertIdSql(model, dynaClass) : null;
-        PreparedStatement statement  = null;
+        String insertSql        = createInsertSql(model, dynaClass, 
properties, null);
+        String queryIdentitySql = null;
 
         if (_log.isDebugEnabled())
         {
             _log.debug("About to execute SQL: " + insertSql);
         }
-        if ((autoIncrColumns.length > 0) && (queryIdSql == null))
+
+        if (autoIncrColumns.length > 0)
         {
-            _log.warn("The database does not support querying for 
auto-generated column values");
+            if (!getPlatformInfo().isLastIdentityValueReadable())
+            {
+                _log.warn("The database does not support querying for 
auto-generated column values");
+            }
+            else
+            {
+                queryIdentitySql = createSelectLastInsertIdSql(model, 
dynaClass);
+            }
         }
 
+        boolean           autoCommitMode = false;
+        PreparedStatement statement      = null;
+
         try
         {
+            if 
(!getPlatformInfo().isAutoCommitModeForLastIdentityValueReading())
+            {
+                autoCommitMode = connection.getAutoCommit();
+                connection.setAutoCommit(false);
+            }
+
             statement = connection.prepareStatement(insertSql);
 
             for (int idx = 0; idx < properties.length; idx++ )
@@ -1165,8 +1181,8 @@
             if (count != 1)
             {
                 _log.warn("Attempted to insert a single row " + dynaBean +
-                         " in table " + dynaClass.getTableName() +
-                         " but changed " + count + " row(s)");
+                          " in table " + dynaClass.getTableName() +
+                          " but changed " + count + " row(s)");
             }
         }
         catch (SQLException ex)
@@ -1177,23 +1193,27 @@
         {
             closeStatement(statement);
         }
-        if (queryIdSql != null)
+        if (queryIdentitySql != null)
         {
             Statement queryStmt       = null;
             ResultSet lastInsertedIds = null;
 
             try
             {
-                // we'll have to commit the statement(s) because otherwise 
most likely
-                // the auto increment hasn't happened yet (the db didn't 
actually
-                // perform the insert yet so no triggering of sequences did 
occur)
-                if (!connection.getAutoCommit())
+                if 
(getPlatformInfo().isAutoCommitModeForLastIdentityValueReading())
                 {
-                    connection.commit();
+                    // we'll commit the statement(s) if no auto-commit is 
enabled because
+                    // otherwise it is possible that the auto increment hasn't 
happened yet
+                    // (the db didn't actually perform the insert yet so no 
triggering of
+                    // sequences did occur)
+                    if (!connection.getAutoCommit())
+                    {
+                        connection.commit();
+                    }
                 }
 
                 queryStmt       = connection.createStatement();
-                lastInsertedIds = queryStmt.executeQuery(queryIdSql);
+                lastInsertedIds = queryStmt.executeQuery(queryIdentitySql);
 
                 lastInsertedIds.next();
 
@@ -1202,7 +1222,7 @@
                     // we're using the index rather than the name because we 
cannot know how
                     // the SQL statement looks like; rather we assume that we 
get the values
                     // back in the same order as the auto increment columns
-                    Object value = lastInsertedIds.getObject(idx + 1);
+                    Object value = getObjectFromResultSet(lastInsertedIds, 
autoIncrColumns[idx], idx + 1);
 
                     PropertyUtils.setProperty(dynaBean, 
autoIncrColumns[idx].getName(), value);
                 }
@@ -1221,7 +1241,7 @@
             }
             catch (SQLException ex)
             {
-                throw new DynaSqlException("Error while retrieving the 
auto-generated primary key from the database", ex);
+                throw new DynaSqlException("Error while retrieving the 
identity column value(s) from the database", ex);
             }
             finally
             {
@@ -1239,6 +1259,19 @@
                 closeStatement(statement);
             }
         }
+        if (!getPlatformInfo().isAutoCommitModeForLastIdentityValueReading())
+        {
+            try
+            {
+                // we need to do a manual commit now
+                connection.commit();
+                connection.setAutoCommit(autoCommitMode);
+            }
+            catch (SQLException ex)
+            {
+                throw new DynaSqlException(ex);
+            }
+        }
     }
 
     /**
@@ -1882,7 +1915,7 @@
                 // we should not use the Clob interface if the database 
doesn't map to this type 
                 jdbcType = targetJdbcType;
             }
-            value = extractColumnValue(resultSet, columnName, jdbcType);
+            value = extractColumnValue(resultSet, columnName, 0, jdbcType);
         }
         else
         {
@@ -1891,66 +1924,106 @@
         return resultSet.wasNull() ? null : value;
     }
 
+    /**
+     * Helper method esp. for the [EMAIL PROTECTED] 
ModelBasedResultSetIterator} class that retrieves
+     * the value for a column from the given result set. If a table was 
specified,
+     * and it contains the column, then the jdbc type defined for the column 
is used for extracting
+     * the value, otherwise the object directly retrieved from the result set 
is returned.<br/>
+     * The method is defined here rather than in the [EMAIL PROTECTED] 
ModelBasedResultSetIterator} class
+     * so that concrete platforms can modify its behavior.
+     * 
+     * @param resultSet  The result set
+     * @param columnName The name of the column
+     * @param table      The table
+     * @return The value
+     */
+    protected Object getObjectFromResultSet(ResultSet resultSet, Column 
column, int idx) throws SQLException
+    {
+        int    originalJdbcType = column.getTypeCode();
+        int    targetJdbcType   = 
getPlatformInfo().getTargetJdbcType(originalJdbcType);
+        int    jdbcType         = originalJdbcType;
+        Object value            = null;
+
+        // in general we're trying to retrieve the value using the original 
type
+        // but sometimes we also need the target type:
+        if ((originalJdbcType == Types.BLOB) && (targetJdbcType != Types.BLOB))
+        {
+            // we should not use the Blob interface if the database doesn't 
map to this type 
+            jdbcType = targetJdbcType;
+        }
+        if ((originalJdbcType == Types.CLOB) && (targetJdbcType != Types.CLOB))
+        {
+            // we should not use the Clob interface if the database doesn't 
map to this type 
+            jdbcType = targetJdbcType;
+        }
+        value = extractColumnValue(resultSet, null, idx, jdbcType);
+        return resultSet.wasNull() ? null : value;
+    }
+
        /**
         * This is the core method to retrieve a value for a column from a 
result set. Its  primary
         * purpose is to call the appropriate method on the result set, and to 
provide an extension
         * point where database-specific implementations can change this 
behavior.
         * 
         * @param resultSet  The result set to extract the value from
-        * @param columnName The name of the column
+        * @param columnName The name of the column; can be <code>null</code> 
in which case the
+     *                   <code>columnIdx</code> will be used instead
+     * @param columnIdx  The index of the column's value in the result set; is 
only used if
+     *                   <code>columnName</code> is <code>null</code>
         * @param jdbcType   The jdbc type to extract
         * @return The value
         * @throws SQLException If an error occurred while accessing the result 
set
         */
-       protected Object extractColumnValue(ResultSet resultSet, String 
columnName, int jdbcType) throws SQLException
+       protected Object extractColumnValue(ResultSet resultSet, String 
columnName, int columnIdx, int jdbcType) throws SQLException
        {
-               Object value;
+        boolean useIdx = (columnName == null);
+               Object  value;
 
                switch (jdbcType)
                {
                    case Types.CHAR:
                    case Types.VARCHAR:
                    case Types.LONGVARCHAR:
-                       value = resultSet.getString(columnName);
+                       value = useIdx ? resultSet.getString(columnIdx) : 
resultSet.getString(columnName);
                        break;
                    case Types.NUMERIC:
                    case Types.DECIMAL:
-                       value = resultSet.getBigDecimal(columnName);
+                       value = useIdx ? resultSet.getBigDecimal(columnIdx) : 
resultSet.getBigDecimal(columnName);
                        break;
                    case Types.BIT:
-                       value = new Boolean(resultSet.getBoolean(columnName));
+                       value = new Boolean(useIdx ? 
resultSet.getBoolean(columnIdx) : resultSet.getBoolean(columnName));
                        break;
                    case Types.TINYINT:
                    case Types.SMALLINT:
                    case Types.INTEGER:
-                       value = new Integer(resultSet.getInt(columnName));
+                       value = new Integer(useIdx ? 
resultSet.getInt(columnIdx) : resultSet.getInt(columnName));
                        break;
                    case Types.BIGINT:
-                       value = new Long(resultSet.getLong(columnName));
+                       value = new Long(useIdx ? resultSet.getLong(columnIdx) 
: resultSet.getLong(columnName));
                        break;
                    case Types.REAL:
-                       value = new Float(resultSet.getFloat(columnName));
+                       value = new Float(useIdx ? 
resultSet.getFloat(columnIdx) : resultSet.getFloat(columnName));
                        break;
                    case Types.FLOAT:
                    case Types.DOUBLE:
-                       value = new Double(resultSet.getDouble(columnName));
+                       value = new Double(useIdx ? 
resultSet.getDouble(columnIdx) : resultSet.getDouble(columnName));
                        break;
                    case Types.BINARY:
                    case Types.VARBINARY:
                    case Types.LONGVARBINARY:
-                       value = resultSet.getBytes(columnName);
+                       value = useIdx ? resultSet.getBytes(columnIdx) : 
resultSet.getBytes(columnName);
                        break;
                    case Types.DATE:
-                       value = resultSet.getDate(columnName);
+                       value = useIdx ? resultSet.getDate(columnIdx) : 
resultSet.getDate(columnName);
                        break;
                    case Types.TIME:
-                       value = resultSet.getTime(columnName);
+                       value = useIdx ? resultSet.getTime(columnIdx) : 
resultSet.getTime(columnName);
                        break;
                    case Types.TIMESTAMP:
-                       value = resultSet.getTimestamp(columnName);
+                       value = useIdx ? resultSet.getTimestamp(columnIdx) : 
resultSet.getTimestamp(columnName);
                        break;
                    case Types.CLOB:
-                       Clob clob = resultSet.getClob(columnName);
+                       Clob clob = useIdx ? resultSet.getClob(columnIdx) : 
resultSet.getClob(columnName);
 
                 if (clob == null)
                 {
@@ -1978,7 +2051,7 @@
                 }
                        break;
                    case Types.BLOB:
-                       Blob blob = resultSet.getBlob(columnName);
+                       Blob blob = useIdx ? resultSet.getBlob(columnIdx) : 
resultSet.getBlob(columnName);
 
                 if (blob == null)
                 {
@@ -2006,21 +2079,21 @@
                 }
                        break;
                    case Types.ARRAY:
-                       value = resultSet.getArray(columnName);
+                       value = useIdx ? resultSet.getArray(columnIdx) : 
resultSet.getArray(columnName);
                        break;
                    case Types.REF:
-                       value = resultSet.getRef(columnName);
+                       value = useIdx ? resultSet.getRef(columnIdx) : 
resultSet.getRef(columnName);
                        break;
                    default:
                        // special handling for Java 1.4/JDBC 3 types
                        if (Jdbc3Utils.supportsJava14JdbcTypes() &&
                            (jdbcType == Jdbc3Utils.determineBooleanTypeCode()))
                        {
-                           value = new 
Boolean(resultSet.getBoolean(columnName));
+                           value = new Boolean(useIdx ? 
resultSet.getBoolean(columnIdx) : resultSet.getBoolean(columnName));
                        }
                        else
                        {
-                           value = resultSet.getObject(columnName);
+                           value = useIdx ? resultSet.getObject(columnIdx) : 
resultSet.getObject(columnName);
                        }
                        break;
                }

Modified: 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java?rev=415112&r1=415111&r2=415112&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 Sun 
Jun 18 02:06:16 2006
@@ -1805,7 +1805,7 @@
      * @param table The table
      * @return The sql, or <code>null</code> if the database does not support 
this
      */
-    public String getSelectLastInsertId(Table table)
+    public String getSelectLastIdentityValues(Table table)
     {
         // No default possible as the databases are quite different in this 
respect
         return null;


Reply via email to