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;