|
From: <hib...@li...> - 2006-06-22 19:56:00
|
Author: ste...@jb...
Date: 2006-06-22 15:51:43 -0400 (Thu, 22 Jun 2006)
New Revision: 10040
Added:
trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java
trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java
trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java
Modified:
trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java
trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd
trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java
trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java
trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java
trunk/Hibernate3/src/org/hibernate/mapping/Collection.java
trunk/Hibernate3/src/org/hibernate/mapping/Join.java
trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java
trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java
trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java
trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/SingleTableEntityPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/UnionSubclassEntityPersister.java
trunk/Hibernate3/src/org/hibernate/tool/hbm2ddl/SchemaExport.java
Log:
HHH-1792 - proper CallableStatement processing;
HHH-1507 - mapping DTD typo;
log SQLWarnings on SchemaExport
Modified: trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -22,6 +22,7 @@
import org.hibernate.engine.FilterDefinition;
import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.Versioning;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.Array;
@@ -668,23 +669,20 @@
throws MappingException {
Element element = node.element( "sql-insert" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element );
- model.setCustomSQLInsert( element.getTextTrim(), callable );
+ boolean callable = isCallable( element );
+ model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-delete" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element );
- model.setCustomSQLDelete( element.getTextTrim(), callable );
+ boolean callable = isCallable( element );
+ model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-update" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element );
- model.setCustomSQLUpdate( element.getTextTrim(), callable );
+ boolean callable = isCallable( element );
+ model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "loader" );
@@ -696,53 +694,46 @@
private static void handleCustomSQL(Element node, Join model) throws MappingException {
Element element = node.element( "sql-insert" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element );
- model.setCustomSQLInsert( element.getTextTrim(), callable );
+ boolean callable = isCallable( element );
+ model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-delete" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element );
- model.setCustomSQLDelete( element.getTextTrim(), callable );
+ boolean callable = isCallable( element );
+ model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-update" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element );
- model.setCustomSQLUpdate( element.getTextTrim(), callable );
+ boolean callable = isCallable( element );
+ model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
}
private static void handleCustomSQL(Element node, Collection model) throws MappingException {
Element element = node.element( "sql-insert" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element, true );
- model.setCustomSQLInsert( element.getTextTrim(), callable );
+ boolean callable = isCallable( element, true );
+ model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-delete" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element, true );
- model.setCustomSQLDelete( element.getTextTrim(), callable );
+ boolean callable = isCallable( element, true );
+ model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-update" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element, true );
- model.setCustomSQLUpdate( element.getTextTrim(), callable );
+ boolean callable = isCallable( element, true );
+ model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
element = node.element( "sql-delete-all" );
if ( element != null ) {
- boolean callable = false;
- callable = isCallable( element, true );
- model.setCustomSQLDeleteAll( element.getTextTrim(), callable );
+ boolean callable = isCallable( element, true );
+ model.setCustomSQLDeleteAll( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
}
}
@@ -762,6 +753,16 @@
return false;
}
+ private static ExecuteUpdateResultCheckStyle getResultCheckStyle(Element element, boolean callable) throws MappingException {
+ Attribute attr = element.attribute( "check" );
+ if ( attr == null ) {
+ // use COUNT as the default. This mimics the old behavior, although
+ // NONE might be a better option moving forward in the case of callable
+ return ExecuteUpdateResultCheckStyle.COUNT;
+ }
+ return ExecuteUpdateResultCheckStyle.parse( attr.getValue() );
+ }
+
public static void bindUnionSubclass(Element node, UnionSubclass unionSubclass,
Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
Added: trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -0,0 +1,73 @@
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
+
+/**
+ * For persistence operations (INSERT, UPDATE, DELETE) what style of determining
+ * results (success/failure) is to be used.
+ *
+ * @author Steve Ebersole
+ */
+public class ExecuteUpdateResultCheckStyle implements Serializable {
+ /**
+ * Do not perform checking. Either user simply does not want checking, or is
+ * indicating a {@link java.sql.CallableStatement} execution in which the
+ * checks are being performed explicitly and failures are handled through
+ * propogation of {@link java.sql.SQLException}s.
+ */
+ public static final ExecuteUpdateResultCheckStyle NONE = new ExecuteUpdateResultCheckStyle( "none" );
+ /**
+ * Perform row-count checking. Row counts are the int values returned by both
+ * {@link java.sql.PreparedStatement#executeUpdate()} and
+ * {@link java.sql.Statement#executeBatch()}. These values are checked
+ * against some expected count.
+ */
+ public static final ExecuteUpdateResultCheckStyle COUNT = new ExecuteUpdateResultCheckStyle( "rowcount" );
+ /**
+ * Essentially the same as {@link #COUNT} except that the row count actually
+ * comes from an output parameter registered as part of a
+ * {@link java.sql.CallableStatement}. This style explicitly prohibits
+ * statement batching from being used...
+ */
+ public static final ExecuteUpdateResultCheckStyle PARAM = new ExecuteUpdateResultCheckStyle( "param" );
+
+ private final String name;
+
+ private ExecuteUpdateResultCheckStyle(String name) {
+ this.name = name;
+ }
+
+ private Object readResolve() throws ObjectStreamException {
+ Object resolved = parse( name );
+ if ( resolved == null ) {
+ throw new InvalidObjectException( "unknown result style [" + name + "]" );
+ }
+ return resolved;
+ }
+
+ public static ExecuteUpdateResultCheckStyle parse(String name) {
+ if ( name.equals( NONE.name ) ) {
+ return NONE;
+ }
+ else if ( name.equals( COUNT.name ) ) {
+ return COUNT;
+ }
+ else if ( name.equals( PARAM.name ) ) {
+ return PARAM;
+ }
+ else {
+ return null;
+ }
+ }
+
+ public static ExecuteUpdateResultCheckStyle determineDefault(String customSql, boolean callable) {
+ if ( customSql == null ) {
+ return COUNT;
+ }
+ else {
+ return callable ? PARAM : COUNT;
+ }
+ }
+}
Modified: trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd 2006-06-22 19:51:43 UTC (rev 10040)
@@ -377,7 +377,7 @@
<!-- Declares a one-to-one association between two entities (Or from a component,
component element, etc. to an entity). -->
-<!ELEMENT one-to-one (meta*|formula*)>
+<!ELEMENT one-to-one (meta*,formula*)>
<!ATTLIST one-to-one name CDATA #REQUIRED>
<!ATTLIST one-to-one formula CDATA #IMPLIED>
<!ATTLIST one-to-one access CDATA #IMPLIED>
@@ -990,16 +990,20 @@
<!-- custom sql operations -->
<!ELEMENT sql-insert (#PCDATA)>
- <!ATTLIST sql-insert callable (true|false) "false">
+ <!ATTLIST sql-insert callable (true|false) "false">
+ <!ATTLIST sql-insert check (none|rowcount|param) #IMPLIED>
<!ELEMENT sql-update (#PCDATA)>
- <!ATTLIST sql-update callable (true|false) "false">
+ <!ATTLIST sql-update callable (true|false) "false">
+ <!ATTLIST sql-update check (none|rowcount|param) #IMPLIED>
<!ELEMENT sql-delete (#PCDATA)>
- <!ATTLIST sql-delete callable (true|false) "false">
+ <!ATTLIST sql-delete callable (true|false) "false">
+ <!ATTLIST sql-delete check (none|rowcount|param) #IMPLIED>
<!ELEMENT sql-delete-all (#PCDATA)>
<!ATTLIST sql-delete-all callable (true|false) "false">
+ <!ATTLIST sql-delete-all check (none|rowcount|param) #IMPLIED>
<!--
Element for defining "auxiliary" database objects. Must be one of two forms:
Modified: trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -86,7 +86,7 @@
* (might be called many times before a single call to <tt>executeBatch()</tt>).
* After setting parameters, call <tt>addToBatch</tt> - do not execute the
* statement explicitly.
- * @see Batcher#addToBatch(int)
+ * @see Batcher#addToBatch
*/
public PreparedStatement prepareBatchStatement(String sql) throws SQLException, HibernateException;
@@ -95,7 +95,7 @@
* (might be called many times before a single call to <tt>executeBatch()</tt>).
* After setting parameters, call <tt>addToBatch</tt> - do not execute the
* statement explicitly.
- * @see Batcher#addToBatch(int)
+ * @see Batcher#addToBatch
*/
public CallableStatement prepareBatchCallableStatement(String sql) throws SQLException, HibernateException;
@@ -103,7 +103,7 @@
* Add an insert / delete / update to the current batch (might be called multiple times
* for single <tt>prepareBatchStatement()</tt>)
*/
- public void addToBatch(int expectedRowCount) throws SQLException, HibernateException;
+ public void addToBatch(Expectation expectation) throws SQLException, HibernateException;
/**
* Execute the batch
Modified: trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -16,96 +16,58 @@
public class BatchingBatcher extends AbstractBatcher {
private int batchSize;
- private int[] expectedRowCounts;
+ private Expectation[] expectations;
public BatchingBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
- super( connectionManager, interceptor );
- expectedRowCounts = new int[ getFactory().getSettings().getJdbcBatchSize() ];
+ super( connectionManager, interceptor );
+ expectations = new Expectation[ getFactory().getSettings().getJdbcBatchSize() ];
}
- public void addToBatch(int expectedRowCount) throws SQLException, HibernateException {
-
- log.trace("Adding to batch");
+ public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
+ if ( !expectation.canBeBatched() ) {
+ throw new HibernateException( "attempting to batch an operation which cannot be batched" );
+ }
PreparedStatement batchUpdate = getStatement();
batchUpdate.addBatch();
- expectedRowCounts[ batchSize++ ] = expectedRowCount;
- if ( batchSize==getFactory().getSettings().getJdbcBatchSize() ) {
- //try {
- doExecuteBatch(batchUpdate);
- /*}
- catch (SQLException sqle) {
- closeStatement(batchUpdate);
- throw sqle;
- }
- catch (HibernateException he) {
- closeStatement(batchUpdate);
- throw he;
- }*/
+ expectations[ batchSize++ ] = expectation;
+ if ( batchSize == getFactory().getSettings().getJdbcBatchSize() ) {
+ doExecuteBatch( batchUpdate );
}
-
}
protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
-
- if (batchSize==0) {
- log.debug("no batched statements to execute");
+ if ( batchSize == 0 ) {
+ log.debug( "no batched statements to execute" );
}
else {
-
- if ( log.isDebugEnabled() ) log.debug("Executing batch size: " + batchSize );
-
+ if ( log.isDebugEnabled() ) {
+ log.debug( "Executing batch size: " + batchSize );
+ }
+
try {
- checkRowCounts( ps.executeBatch() );
+ checkRowCounts( ps.executeBatch(), ps );
}
catch (RuntimeException re) {
- log.error("Exception executing batch: ", re);
+ log.error( "Exception executing batch: ", re );
throw re;
}
finally {
- batchSize=0;
- //ps.clearBatch();
+ batchSize = 0;
}
-
+
}
}
- private void checkRowCounts(int[] rowCounts) {
- int rowCountLength = rowCounts.length;
- if ( rowCountLength!=batchSize ) {
- log.warn("JDBC driver did not return the expected number of row counts");
+ private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
+ int numberOfRowCounts = rowCounts.length;
+ if ( numberOfRowCounts != batchSize ) {
+ log.warn( "JDBC driver did not return the expected number of row counts" );
}
- for ( int i=0; i<rowCountLength; i++ ) {
- checkRowCount( rowCounts[i], expectedRowCounts[i], i );
+ for ( int i = 0; i < numberOfRowCounts; i++ ) {
+ expectations[i].verifyOutcome( rowCounts[i], ps, i );
}
}
-
- private void checkRowCount(int rowCount, int expectedRowCount, int i) {
- if ( rowCount==-2 ) {
- if ( log.isDebugEnabled() ) log.debug("success of batch update unknown: " + i);
- }
- else if ( rowCount==-3 ) {
- throw new HibernateException("Batch update failed: " + i);
- }
- else {
- if ( expectedRowCount>=0 ) {
- if ( rowCount<expectedRowCount ) {
- throw new StaleStateException(
- "Batch update returned unexpected row count from update: " + i +
- " actual row count: " + rowCount +
- " expected: " + expectedRowCount
- );
- }
- if ( rowCount>expectedRowCount ) {
- throw new HibernateException(
- "Batch update returned unexpected row count from update: " + i +
- " actual row count: " + rowCount +
- " expected: " + expectedRowCount
- );
- }
- }
- }
- }
}
Added: trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -0,0 +1,17 @@
+package org.hibernate.jdbc;
+
+import org.hibernate.HibernateException;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+/**
+ * Defines an expected DML operation outcome.
+ *
+ * @author Steve Ebersole
+ */
+public interface Expectation {
+ public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) throws SQLException, HibernateException;
+ public int prepare(PreparedStatement statement) throws SQLException, HibernateException;
+ public boolean canBeBatched();
+}
Added: trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -0,0 +1,176 @@
+package org.hibernate.jdbc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.StaleStateException;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.util.JDBCExceptionReporter;
+import org.hibernate.exception.GenericJDBCException;
+
+import java.sql.CallableStatement;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Types;
+
+/**
+ * Holds various often used {@link Expectation} definitions.
+ *
+ * @author Steve Ebersole
+ */
+public class Expectations {
+ private static final Log log = LogFactory.getLog( Expectations.class );
+
+ public static final int USUAL_EXPECTED_COUNT = 1;
+ public static final int USUAL_PARAM_POSITION = 1;
+
+
+ // Base Expectation impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public static class BasicExpectation implements Expectation {
+ private final int expectedRowCount;
+
+ protected BasicExpectation(int expectedRowCount) {
+ this.expectedRowCount = expectedRowCount;
+ if ( expectedRowCount < 0 ) {
+ throw new IllegalArgumentException( "Expected row count must be greater than zero" );
+ }
+ }
+
+ public final void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
+ rowCount = determineRowCount( rowCount, statement );
+ if ( batchPosition < 0 ) {
+ checkNonBatched( rowCount );
+ }
+ else {
+ checkBatched( rowCount, batchPosition );
+ }
+ }
+
+ private void checkBatched(int rowCount, int batchPosition) {
+ if ( rowCount == -2 ) {
+ if ( log.isDebugEnabled() ) {
+ log.debug( "success of batch update unknown: " + batchPosition );
+ }
+ }
+ else if ( rowCount == -3 ) {
+ throw new HibernateException( "Batch update failed: " + batchPosition );
+ }
+ else {
+ if ( expectedRowCount > rowCount ) {
+ throw new StaleStateException(
+ "Batch update returned unexpected row count from update [" + batchPosition +
+ "]; actual row count: " + rowCount +
+ "; expected: " + expectedRowCount
+ );
+ }
+ if ( expectedRowCount < rowCount ) {
+ throw new HibernateException(
+ "Batch update returned unexpected row count from update [" + batchPosition +
+ "]; actual row count: " + rowCount +
+ "; expected: " + expectedRowCount
+ );
+ }
+ }
+ }
+
+ private void checkNonBatched(int rowCount) {
+ if ( expectedRowCount > rowCount ) {
+ throw new StaleStateException(
+ "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount
+ );
+ }
+ if ( expectedRowCount < rowCount ) {
+ throw new HibernateException(
+ "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount
+ );
+ }
+ }
+
+ public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
+ return 0;
+ }
+
+ public boolean canBeBatched() {
+ return true;
+ }
+
+ protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
+ return reportedRowCount;
+ }
+ }
+
+ public static class BasicParamExpectation extends BasicExpectation {
+ private final int parameterPosition;
+ protected BasicParamExpectation(int expectedRowCount, int parameterPosition) {
+ super( expectedRowCount );
+ this.parameterPosition = parameterPosition;
+ }
+
+ public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
+ toCallableStatement( statement ).registerOutParameter( parameterPosition, Types.NUMERIC );
+ return 1;
+ }
+
+ public boolean canBeBatched() {
+ return false;
+ }
+
+ protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
+ try {
+ return toCallableStatement( statement ).getInt( parameterPosition );
+ }
+ catch( SQLException sqle ) {
+ JDBCExceptionReporter.logExceptions( sqle, "could not extract row counts from CallableStatement" );
+ throw new GenericJDBCException( "could not extract row counts from CallableStatement", sqle );
+ }
+ }
+
+ private CallableStatement toCallableStatement(PreparedStatement statement) {
+ if ( ! CallableStatement.class.isInstance( statement ) ) {
+ throw new HibernateException( "BasicParamExpectation operates exclusively on CallableStatements : " + statement.getClass() );
+ }
+ return ( CallableStatement ) statement;
+ }
+ }
+
+
+ // Various Expectation instances ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public static final Expectation NONE = new Expectation() {
+ public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
+ // explicitly perform no checking...
+ }
+
+ public int prepare(PreparedStatement statement) {
+ return 0;
+ }
+
+ public boolean canBeBatched() {
+ return true;
+ }
+ };
+
+ public static final Expectation BASIC = new BasicExpectation( USUAL_EXPECTED_COUNT );
+
+ public static final Expectation PARAM = new BasicParamExpectation( USUAL_EXPECTED_COUNT, USUAL_PARAM_POSITION );
+
+
+ public static Expectation appropriateExpectation(ExecuteUpdateResultCheckStyle style) {
+ if ( style == ExecuteUpdateResultCheckStyle.NONE ) {
+ return NONE;
+ }
+ else if ( style == ExecuteUpdateResultCheckStyle.COUNT ) {
+ return BASIC;
+ }
+ else if ( style == ExecuteUpdateResultCheckStyle.PARAM ) {
+ return PARAM;
+ }
+ else {
+ throw new HibernateException( "unknown check style : " + style );
+ }
+ }
+
+ private Expectations() {
+ }
+}
Modified: trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -6,7 +6,6 @@
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
-import org.hibernate.StaleStateException;
/**
* An implementation of the <tt>Batcher</tt> interface that does no batching
@@ -19,23 +18,10 @@
super( connectionManager, interceptor );
}
- public void addToBatch(int expectedRowCount) throws SQLException, HibernateException {
- final int rowCount = getStatement().executeUpdate();
- //negative expected row count means we don't know how many rows to expect
- if ( expectedRowCount>0 ) {
- if ( expectedRowCount>rowCount ) {
- throw new StaleStateException(
- "Unexpected row count: " + rowCount +
- " expected: " + expectedRowCount
- );
- }
- if ( expectedRowCount<rowCount ) {
- throw new HibernateException(
- "Unexpected row count: " + rowCount +
- " expected: " + expectedRowCount
- );
- }
- }
+ public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
+ PreparedStatement statement = getStatement();
+ final int rowCount = statement.executeUpdate();
+ expectation.verifyOutcome( rowCount, statement, 0 );
}
protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
Modified: trunk/Hibernate3/src/org/hibernate/mapping/Collection.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/mapping/Collection.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/mapping/Collection.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -9,6 +9,7 @@
import org.hibernate.FetchMode;
import org.hibernate.MappingException;
import org.hibernate.engine.Mapping;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;
@@ -60,13 +61,17 @@
private final java.util.Set synchronizedTables = new HashSet();
private String customSQLInsert;
+ private boolean customInsertCallable;
+ private ExecuteUpdateResultCheckStyle insertCheckStyle;
private String customSQLUpdate;
+ private boolean customUpdateCallable;
+ private ExecuteUpdateResultCheckStyle updateCheckStyle;
private String customSQLDelete;
+ private boolean customDeleteCallable;
+ private ExecuteUpdateResultCheckStyle deleteCheckStyle;
private String customSQLDeleteAll;
- private boolean customInsertCallable;
- private boolean customUpdateCallable;
- private boolean customDeleteCallable;
private boolean customDeleteAllCallable;
+ private ExecuteUpdateResultCheckStyle deleteAllCheckStyle;
private String loaderName;
@@ -402,58 +407,80 @@
this.cacheRegionName = cacheRegionName;
}
- public String getCustomSQLDelete() {
- return customSQLDelete;
- }
- public void setCustomSQLDelete(String customSQLDelete, boolean callable) {
- this.customSQLDelete = customSQLDelete;
- this.customDeleteCallable = callable;
+
+ public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+ this.customSQLInsert = customSQLInsert;
+ this.customInsertCallable = callable;
+ this.insertCheckStyle = checkStyle;
}
- public String getCustomSQLDeleteAll() {
- return customSQLDeleteAll;
+ public String getCustomSQLInsert() {
+ return customSQLInsert;
}
- public void setCustomSQLDeleteAll(String customSQLDeleteAll, boolean callable) {
- this.customSQLDeleteAll = customSQLDeleteAll;
- this.customDeleteAllCallable = callable;
+ public boolean isCustomInsertCallable() {
+ return customInsertCallable;
}
- public String getCustomSQLInsert() {
- return customSQLInsert;
+ public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
+ return insertCheckStyle;
}
- public void setCustomSQLInsert(String customSQLInsert, boolean callable) {
- this.customSQLInsert = customSQLInsert;
- this.customInsertCallable = callable;
+ public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+ this.customSQLUpdate = customSQLUpdate;
+ this.customUpdateCallable = callable;
+ this.updateCheckStyle = checkStyle;
}
public String getCustomSQLUpdate() {
return customSQLUpdate;
}
- public void setCustomSQLUpdate(String customSQLUpdate, boolean callable) {
- this.customSQLUpdate = customSQLUpdate;
- this.customUpdateCallable = callable;
+ public boolean isCustomUpdateCallable() {
+ return customUpdateCallable;
}
+ public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
+ return updateCheckStyle;
+ }
+
+ public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+ this.customSQLDelete = customSQLDelete;
+ this.customDeleteCallable = callable;
+ this.deleteCheckStyle = checkStyle;
+ }
+
+ public String getCustomSQLDelete() {
+ return customSQLDelete;
+ }
+
public boolean isCustomDeleteCallable() {
return customDeleteCallable;
}
+ public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
+ return deleteCheckStyle;
+ }
+
+ public void setCustomSQLDeleteAll(String customSQLDeleteAll, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+ this.customSQLDeleteAll = customSQLDeleteAll;
+ this.customDeleteAllCallable = callable;
+ this.deleteAllCheckStyle = checkStyle;
+ }
+
+ public String getCustomSQLDeleteAll() {
+ return customSQLDeleteAll;
+ }
+
public boolean isCustomDeleteAllCallable() {
return customDeleteAllCallable;
}
- public boolean isCustomInsertCallable() {
- return customInsertCallable;
+ public ExecuteUpdateResultCheckStyle getCustomSQLDeleteAllCheckStyle() {
+ return deleteAllCheckStyle;
}
- public boolean isCustomUpdateCallable() {
- return customUpdateCallable;
- }
-
public void addFilter(String name, String condition) {
filters.put( name, condition );
}
Modified: trunk/Hibernate3/src/org/hibernate/mapping/Join.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/mapping/Join.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/mapping/Join.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -6,6 +6,7 @@
import java.util.Iterator;
import org.hibernate.sql.Alias;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
/**
* @author Gavin King
@@ -24,11 +25,14 @@
// Custom SQL
private String customSQLInsert;
+ private boolean customInsertCallable;
+ private ExecuteUpdateResultCheckStyle insertCheckStyle;
private String customSQLUpdate;
+ private boolean customUpdateCallable;
+ private ExecuteUpdateResultCheckStyle updateCheckStyle;
private String customSQLDelete;
- private boolean customInsertCallable;
- private boolean customUpdateCallable;
private boolean customDeleteCallable;
+ private ExecuteUpdateResultCheckStyle deleteCheckStyle;
public void addProperty(Property prop) {
properties.add(prop);
@@ -81,44 +85,60 @@
return properties.size();
}
- public String getCustomSQLDelete() {
- return customSQLDelete;
+ public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+ this.customSQLInsert = customSQLInsert;
+ this.customInsertCallable = callable;
+ this.insertCheckStyle = checkStyle;
}
- public void setCustomSQLDelete(String customSQLDelete, boolean callable) {
- this.customSQLDelete = customSQLDelete;
- this.customDeleteCallable = callable;
- }
-
public String getCustomSQLInsert() {
return customSQLInsert;
}
- public void setCustomSQLInsert(String customSQLInsert, boolean callable) {
- this.customSQLInsert = customSQLInsert;
- this.customInsertCallable = callable;
+ public boolean isCustomInsertCallable() {
+ return customInsertCallable;
}
- public String getCustomSQLUpdate() {
- return customSQLUpdate;
+ public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
+ return insertCheckStyle;
}
- public void setCustomSQLUpdate(String customSQLUpdate, boolean callable) {
+ public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLUpdate = customSQLUpdate;
this.customUpdateCallable = callable;
+ this.updateCheckStyle = checkStyle;
}
+ public String getCustomSQLUpdate() {
+ return customSQLUpdate;
+ }
+
+ public boolean isCustomUpdateCallable() {
+ return customUpdateCallable;
+ }
+
+ public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
+ return updateCheckStyle;
+ }
+
+ public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+ this.customSQLDelete = customSQLDelete;
+ this.customDeleteCallable = callable;
+ this.deleteCheckStyle = checkStyle;
+ }
+
+ public String getCustomSQLDelete() {
+ return customSQLDelete;
+ }
+
public boolean isCustomDeleteCallable() {
return customDeleteCallable;
}
- public boolean isCustomInsertCallable() {
- return customInsertCallable;
+ public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
+ return deleteCheckStyle;
}
- public boolean isCustomUpdateCallable() {
- return customUpdateCallable;
- }
public boolean isSequentialSelect() {
return sequentialSelect;
}
@@ -129,7 +149,7 @@
public boolean isInverse() {
return inverse;
}
-
+
public void setInverse(boolean leftJoin) {
this.inverse = leftJoin;
}
@@ -137,7 +157,7 @@
public String toString() {
return getClass().getName() + '(' + table.toString() + ')';
}
-
+
public boolean isLazy() {
Iterator iter = getPropertyIterator();
while ( iter.hasNext() ) {
@@ -146,7 +166,7 @@
}
return true;
}
-
+
public boolean isOptional() {
return optional;
}
Modified: trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -13,6 +13,7 @@
import org.hibernate.EntityMode;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.Mapping;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.sql.Alias;
import org.hibernate.util.EmptyIterator;
import org.hibernate.util.JoinedIterator;
@@ -61,11 +62,14 @@
// Custom SQL
private String customSQLInsert;
+ private boolean customInsertCallable;
+ private ExecuteUpdateResultCheckStyle insertCheckStyle;
private String customSQLUpdate;
+ private boolean customUpdateCallable;
+ private ExecuteUpdateResultCheckStyle updateCheckStyle;
private String customSQLDelete;
- private boolean customInsertCallable;
- private boolean customUpdateCallable;
private boolean customDeleteCallable;
+ private ExecuteUpdateResultCheckStyle deleteCheckStyle;
private String temporaryIdTableName;
private String temporaryIdTableDDL;
@@ -490,9 +494,10 @@
return properties.iterator();
}
- public void setCustomSQLInsert(String customSQLInsert, boolean callable) {
+ public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLInsert = customSQLInsert;
this.customInsertCallable = callable;
+ this.insertCheckStyle = checkStyle;
}
public String getCustomSQLInsert() {
@@ -503,9 +508,14 @@
return customInsertCallable;
}
- public void setCustomSQLUpdate(String customSQLUpdate, boolean callable) {
+ public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
+ return insertCheckStyle;
+ }
+
+ public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLUpdate = customSQLUpdate;
this.customUpdateCallable = callable;
+ this.updateCheckStyle = checkStyle;
}
public String getCustomSQLUpdate() {
@@ -516,9 +526,14 @@
return customUpdateCallable;
}
- public void setCustomSQLDelete(String customSQLDelete, boolean callable) {
+ public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
+ return updateCheckStyle;
+ }
+
+ public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLDelete = customSQLDelete;
this.customDeleteCallable = callable;
+ this.deleteCheckStyle = checkStyle;
}
public String getCustomSQLDelete() {
@@ -529,6 +544,10 @@
return customDeleteCallable;
}
+ public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
+ return deleteCheckStyle;
+ }
+
public void addFilter(String name, String condition) {
filters.put(name, condition);
}
Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -2,11 +2,9 @@
package org.hibernate.persister.collection;
import java.io.Serializable;
-import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.sql.Types;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
@@ -20,6 +18,8 @@
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.TransientObjectException;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.Expectations;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.entry.CacheEntryStructure;
@@ -34,7 +34,7 @@
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SubselectFetch;
-import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator;
@@ -181,6 +181,10 @@
private final boolean updateCallable;
private final boolean deleteCallable;
private final boolean deleteAllCallable;
+ private ExecuteUpdateResultCheckStyle insertCheckStyle;
+ private ExecuteUpdateResultCheckStyle updateCheckStyle;
+ private ExecuteUpdateResultCheckStyle deleteCheckStyle;
+ private ExecuteUpdateResultCheckStyle deleteAllCheckStyle;
private final Serializable[] spaces;
@@ -418,40 +422,56 @@
//GENERATE THE SQL:
//sqlSelectString = sqlSelectString();
- if ( collection.getCustomSQLDeleteAll() == null ) {
- sqlDeleteString = generateDeleteString();
- deleteAllCallable = false;
- }
- else {
- sqlDeleteString = collection.getCustomSQLDeleteAll();
- deleteAllCallable = collection.isCustomDeleteAllCallable();
- }
//sqlSelectRowString = sqlSelectRowString();
+
if ( collection.getCustomSQLInsert() == null ) {
sqlInsertRowString = generateInsertRowString();
insertCallable = false;
+ insertCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
}
else {
sqlInsertRowString = collection.getCustomSQLInsert();
insertCallable = collection.isCustomInsertCallable();
+ insertCheckStyle = collection.getCustomSQLInsertCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLInsert(), insertCallable )
+ : collection.getCustomSQLInsertCheckStyle();
}
if ( collection.getCustomSQLUpdate() == null ) {
sqlUpdateRowString = generateUpdateRowString();
updateCallable = false;
+ updateCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
}
else {
sqlUpdateRowString = collection.getCustomSQLUpdate();
updateCallable = collection.isCustomUpdateCallable();
+ updateCheckStyle = collection.getCustomSQLUpdateCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLUpdate(), insertCallable )
+ : collection.getCustomSQLUpdateCheckStyle();
}
+
if ( collection.getCustomSQLDelete() == null ) {
sqlDeleteRowString = generateDeleteRowString();
deleteCallable = false;
+ deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
}
else {
sqlDeleteRowString = collection.getCustomSQLDelete();
deleteCallable = collection.isCustomDeleteCallable();
+ deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
}
+
+ if ( collection.getCustomSQLDeleteAll() == null ) {
+ sqlDeleteString = generateDeleteString();
+ deleteAllCallable = false;
+ deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
+ }
+ else {
+ sqlDeleteString = collection.getCustomSQLDeleteAll();
+ deleteAllCallable = collection.isCustomDeleteAllCallable();
+ deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
+ }
+
sqlSelectSizeString = generateSelectSizeString( collection.isIndexed() && !collection.isMap() );
sqlDetectRowByIndexString = generateDetectRowByIndexString();
sqlDetectRowByElementString = generateDetectRowByElementString();
@@ -678,8 +698,7 @@
public Object readElement(ResultSet rs, Object owner, String[] aliases, SessionImplementor session)
throws HibernateException, SQLException {
- Object element = getElementType().nullSafeGet( rs, aliases, session, owner );
- return element;
+ return getElementType().nullSafeGet( rs, aliases, session, owner );
}
public Object readIndex(ResultSet rs, String[] aliases, SessionImplementor session)
@@ -891,10 +910,9 @@
}
protected SelectFragment generateSelectFragment(String alias, String columnSuffix) {
- SelectFragment frag = new SelectFragment()
+ return new SelectFragment()
.setSuffix( columnSuffix )
.addColumns( alias, keyColumnNames, keyColumnAliases );
- return frag;
}
protected void appendElementColumns(SelectFragment frag, String elemAlias) {
@@ -944,7 +962,7 @@
return qualify(alias, elementColumnNames, elementFormulaTemplates);
}
- private static final String[] qualify(String alias, String[] columnNames, String[] formulaTemplates) {
+ private static String[] qualify(String alias, String[] columnNames, String[] formulaTemplates) {
int span = columnNames.length;
String[] result = new String[span];
for (int i=0; i<span; i++) {
@@ -998,24 +1016,50 @@
try {
int offset = 1;
PreparedStatement st = null;
- if ( isDeleteCallable() ) {
- CallableStatement callstatement = session.getBatcher()
- .prepareBatchCallableStatement( getSQLDeleteString() );
- callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ?
- st = callstatement;
+ Expectation expectation = Expectations.appropriateExpectation( getDeleteAllCheckStyle() );
+ boolean callable = isDeleteAllCallable();
+ boolean useBatch = expectation.canBeBatched();
+ String sql = getSQLDeleteString();
+ if ( useBatch ) {
+ if ( callable ) {
+ st = session.getBatcher().prepareBatchCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareBatchStatement( sql );
+ }
}
else {
- st = session.getBatcher().prepareBatchStatement( getSQLDeleteString() );
+ if ( callable ) {
+ st = session.getBatcher().prepareCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareStatement( sql );
+ }
}
+
try {
+ offset+= expectation.prepare( st );
+
writeKey( st, id, offset, session );
- session.getBatcher().addToBatch( -1 );
+ if ( useBatch ) {
+ session.getBatcher().addToBatch( expectation );
+ }
+ else {
+ expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+ }
}
catch ( SQLException sqle ) {
- session.getBatcher().abortBatch( sqle );
+ if ( useBatch ) {
+ session.getBatcher().abortBatch( sqle );
+ }
throw sqle;
}
+ finally {
+ if ( !useBatch ) {
+ session.getBatcher().closeStatement( st );
+ }
+ }
if ( log.isDebugEnabled() ) {
log.debug( "done deleting collection" );
@@ -1051,25 +1095,41 @@
//create all the new entries
Iterator entries = collection.entries(this);
if ( entries.hasNext() ) {
- try {
- collection.preInsert( this );
- int i = 0;
- int count = 0;
- while ( entries.hasNext() ) {
+ collection.preInsert( this );
+ int i = 0;
+ int count = 0;
+ while ( entries.hasNext() ) {
- final Object entry = entries.next();
- if ( collection.entryExists( entry, i ) ) {
- int offset = 1;
- PreparedStatement st = null;
- if ( isInsertCallable() ) {
- CallableStatement callstatement = session.getBatcher()
- .prepareBatchCallableStatement( getSQLInsertRowString() );
- callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ?
- st = callstatement;
+ final Object entry = entries.next();
+ if ( collection.entryExists( entry, i ) ) {
+ int offset = 1;
+ PreparedStatement st = null;
+ Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
+ boolean callable = isInsertCallable();
+ boolean useBatch = expectation.canBeBatched();
+ String sql = getSQLInsertRowString();
+
+ if ( useBatch ) {
+ if ( callable ) {
+ st = session.getBatcher().prepareBatchCallableStatement( sql );
}
else {
- st = session.getBatcher().prepareBatchStatement( getSQLInsertRowString() );
+ st = session.getBatcher().prepareBatchStatement( sql );
}
+ }
+ else {
+ if ( callable ) {
+ st = session.getBatcher().prepareCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareStatement( sql );
+ }
+ }
+
+
+ try {
+ offset+= expectation.prepare( st );
+
//TODO: copy/paste from insertRows()
int loc = writeKey( st, id, offset, session );
if ( hasIdentifier ) {
@@ -1078,22 +1138,36 @@
if ( hasIndex /*&& !indexIsFormula*/ ) {
loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );
}
- //if ( !elementIsFormula ) {
- loc = writeElement(st, collection.getElement(entry), loc, session );
- //}
- session.getBatcher().addToBatch( 1 );
+ loc = writeElement(st, collection.getElement(entry), loc, session );
+
+ if ( useBatch ) {
+ session.getBatcher().addToBatch( expectation );
+ }
+ else {
+ expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+ }
+
collection.afterRowInsert( this, entry, i );
count++;
}
- i++;
+ catch ( SQLException sqle ) {
+ if ( useBatch ) {
+ session.getBatcher().abortBatch( sqle );
+ }
+ throw sqle;
+ }
+ finally {
+ if ( !useBatch ) {
+ session.getBatcher().closeStatement( st );
+ }
+ }
+
}
- if ( log.isDebugEnabled() ) {
- log.debug( "done inserting collection: " + count + " rows inserted" );
- }
+ i++;
}
- catch ( SQLException sqle ) {
- session.getBatcher().abortBatch( sqle );
- throw sqle;
+
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done inserting collection: " + count + " rows inserted" );
}
}
@@ -1139,48 +1213,71 @@
if ( deletes.hasNext() ) {
int offset = 1;
int count = 0;
- PreparedStatement st = null;
- if ( isDeleteCallable() ) {
- CallableStatement callstatement = session.getBatcher()
- .prepareBatchCallableStatement( getSQLDeleteRowString() );
- callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ?
- st = callstatement;
- }
- else {
- st = session.getBatcher().prepareBatchStatement( getSQLDeleteRowString() );
- }
+ while ( deletes.hasNext() ) {
+ PreparedStatement st = null;
+ Expectation expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
+ boolean callable = isDeleteCallable();
+ boolean useBatch = expectation.canBeBatched();
+ String sql = getSQLDeleteRowString();
- try {
- int i=0;
- while ( deletes.hasNext() ) {
+ if ( useBatch ) {
+ if ( callable ) {
+ st = session.getBatcher().prepareBatchCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareBatchStatement( sql );
+ }
+ }
+ else {
+ if ( callable ) {
+ st = session.getBatcher().prepareCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareStatement( sql );
+ }
+ }
+
+ try {
+ expectation.prepare( st );
+
Object entry = deletes.next();
int loc = offset;
if ( hasIdentifier ) {
- loc = writeIdentifier( st, entry, loc, session );
+ writeIdentifier( st, entry, loc, session );
}
else {
- //if ( !isOneToMany() ) {
- loc = writeKey( st, id, loc, session );
- //}
- if (deleteByIndex) {
- loc = writeIndexToWhere( st, entry, loc, session );
+ loc = writeKey( st, id, loc, session );
+ if ( deleteByIndex ) {
+ writeIndexToWhere( st, entry, loc, session );
}
else {
- loc = writeElementToWhere( st, entry, loc, session );
+ writeElementToWhere( st, entry, loc, session );
}
}
- session.getBatcher().addToBatch( -1 );
+
+ if ( useBatch ) {
+ session.getBatcher().addToBatch( expectation );
+ }
+ else {
+ expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+ }
count++;
- i++;
}
- }
- catch ( SQLException sqle ) {
- session.getBatcher().abortBatch( sqle );
- throw sqle;
- }
+ catch ( SQLException sqle ) {
+ if ( useBatch ) {
+ session.getBatcher().abortBatch( sqle );
+ }
+ throw sqle;
+ }
+ finally {
+ if ( !useBatch ) {
+ session.getBatcher().closeStatement( st );
+ }
+ }
- if ( log.isDebugEnabled() ) {
- log.debug( "done deleting collection rows: " + count + " deleted" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done deleting collection rows: " + count + " deleted" );
+ }
}
}
else {
@@ -1219,52 +1316,76 @@
try {
//insert all the new entries
- Iterator entries = collection.entries(this);
+ collection.preInsert( this );
+ Iterator entries = collection.entries( this );
+ Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
boolean callable = isInsertCallable();
- try {
- collection.preInsert( this );
- int i = 0;
- int count = 0;
+ boolean useBatch = expectation.canBeBatched();
+ String sql = getSQLInsertRowString();
+ int i = 0;
+ int count = 0;
+ while ( entries.hasNext() ) {
int offset = 1;
- while ( entries.hasNext() ) {
- Object entry = entries.next();
- PreparedStatement st = null;
- if ( collection.needsInserting( entry, i, elementType ) ) {
+ Object entry = entries.next();
+ PreparedStatement st = null;
+ if ( collection.needsInserting( entry, i, elementType ) ) {
+
+ if ( useBatch ) {
if ( st == null ) {
if ( callable ) {
- CallableStatement callstatement = session.getBatcher()
- .prepareBatchCallableStatement( getSQLInsertRowString() );
- callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ?
- st = callstatement;
+ st = session.getBatcher().prepareBatchCallableStatement( sql );
}
else {
- st = session.getBatcher().prepareBatchStatement( getSQLInsertRowString() );
+ st = session.getBatcher().prepareBatchStatement( sql );
}
}
+ }
+ else {
+ if ( callable ) {
+ st = session.getBatcher().prepareCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareStatement( sql );
+ }
+ }
+
+ try {
+ offset += expectation.prepare( st );
//TODO: copy/paste from recreate()
- int loc = writeKey( st, id, offset, session );
+ offset = writeKey( st, id, offset, session );
if ( hasIdentifier ) {
- loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
+ offset = writeIdentifier( st, collection.getIdentifier(entry, i), offset, session );
}
if ( hasIndex /*&& !indexIsFormula*/ ) {
- loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );
+ offset = writeIndex( st, collection.getIndex(entry, i, this), offset, session );
}
- //if ( !elementIsFormula ) {
- loc = writeElement(st, collection.getElement(entry), loc, session );
- //}
- session.getBatcher().addToBatch( 1 );
+ writeElement(st, collection.getElement(entry), offset, session );
+
+ if ( useBatch ) {
+ session.getBatcher().addToBatch( expectation );
+ }
+ else {
+ expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+ }
collection.afterRowInsert( this, entry, i );
count++;
}
- i++;
+ catch ( SQLException sqle ) {
+ if ( useBatch ) {
+ session.getBatcher().abortBatch( sqle );
+ }
+ throw sqle;
+ }
+ finally {
+ if ( !useBatch ) {
+ session.getBatcher().closeStatement( st );
+ }
+ }
}
- if ( log.isDebugEnabled() ) {
- log.debug( "done inserting rows: " + count + " inserted" );
- }
+ i++;
}
- catch ( SQLException sqle ) {
- session.getBatcher().abortBatch( sqle );
- throw sqle;
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done inserting rows: " + count + " inserted" );
}
}
catch ( SQLException sqle ) {
@@ -1432,18 +1553,34 @@
return insertCallable;
}
+ protected ExecuteUpdateResultCheckStyle getInsertCheckStyle() {
+ return insertCheckStyle;
+ }
+
protected boolean isUpdateCallable() {
return updateCallable;
}
+ protected ExecuteUpdateResultCheckStyle getUpdateCheckStyle() {
+ return updateCheckStyle;
+ }
+
protected boolean isDeleteCallable() {
return deleteCallable;
}
+ protected ExecuteUpdateResultCheckStyle getDeleteCheckStyle() {
+ return deleteCheckStyle;
+ }
+
protected boolean isDeleteAllCallable() {
return deleteAllCallable;
}
+ protected ExecuteUpdateResultCheckStyle getDeleteAllCheckStyle() {
+ return deleteAllCheckStyle;
+ }
+
public String toString() {
return StringHelper.unqualify( getClass().getName() ) + '(' + role + ')';
}
Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -2,14 +2,14 @@
package org.hibernate.persister.collection;
import java.io.Serializable;
-import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
-import java.sql.Types;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
+import org.hibernate.jdbc.Expectations;
+import org.hibernate.jdbc.Expectation;
import org.hibernate.type.AssociationType;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.cache.CacheConcurrencyStrategy;
@@ -172,51 +172,76 @@
try {
PreparedStatement st = null;
+ Expectation expectation = Expectations.appropriateExpectation( getUpdateCheckStyle() );
boolean callable = isUpdateCallable();
- Iterator entries = collection.entries(this);
- try {
- int i = 0;
- int count = 0;
- while ( entries.hasNext() ) {
+ boolean useBatch = expectation.canBeBatched();
+ Iterator entries = collection.entries( this );
+ String sql = getSQLUpdateRowString();
+ int i = 0;
+ int count = 0;
+ while ( entries.hasNext() ) {
+ Object entry = entries.next();
+ if ( collection.needsUpdating( entry, i, elementType ) ) {
int offset = 1;
- Object entry = entries.next();
- if ( collection.needsUpdating( entry, i, elementType ) ) {
+
+ if ( useBatch ) {
if ( st == null ) {
if ( callable ) {
- CallableStatement callstatement = session.getBatcher()
- .prepareBatchCallableStatement( getSQLUpdateRowString() );
- callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? (we cant make it return this without changing collectionpersister interface)
- st = callstatement;
+ st = session.getBatcher().prepareBatchCallableStatement( sql );
}
else {
- st = session.getBatcher().prepareBatchStatement( getSQLUpdateRowString() );
+ st = session.getBatcher().prepareBatchStatement( sql );
}
}
-
- int loc = writeElement(st, collection.getElement(entry), offset, session );
+ }
+ else {
+ if ( callable ) {
+ st = session.getBatcher().prepareCallableStatement( sql );
+ }
+ else {
+ st = session.getBatcher().prepareStatement( sql );
+ }
+ }
+
+ try {
+ offset+= expectation.prepare( st );
+ int loc = writeElement( st, collection.getElement( entry ), offset, session );
if ( hasIdentifier ) {
- loc = writeIdentifier(st, collection.getIdentifier(entry, i), loc, session);
+ writeIdentifier( st, collection.getIdentifier( entry, i ), loc, session );
}
else {
loc = writeKey( st, id, loc, session );
if ( hasIndex && !indexContainsFormula ) {
- loc = writeIndexToWhere( st, collection.getIndex(entry, i, this), loc, session );
+ writeIndexToWhere( st, collection.getIndex( entry, i, this ), loc, session );
}
else {
- loc = writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session );
+ writeElementToWhere( st, collection.getSnapshotElement( entry, i ), loc, session );
}
}
- session.getBatcher().addToBatch( 1 );
- count++;
+
+ if ( useBatch ) {
+ session.getBatcher().addToBatch( expectation );
+ }
+ else {
+ expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+ }
}
- i++;
+ catch ( SQLException sqle ) {
+ if ( useBatch ) {
+ session.getBatcher().abortBatch( sqle );
+ }
+ throw sqle;
+ }
+ finally {
+ if ( !useBatch ) {
+ session.getBatcher().closeStatement( st );
+ }
+ }
+ count++;
}
- return count;
+ i++;
}
- catch ( SQLException sqle ) {
- session.getBatcher().abortBatch( sqle );
- throw sqle;
- }
+ return count;
}
catch ( SQLException sqle ) {
throw JDBCExceptionHelper.convert(
Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java 2006-06-21 22:29:24 UTC (rev 10039)
+++ trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java 2006-06-22 19:51:43 UTC (rev 10040)
@@ -2,14 +2,14 @@
package org.hibernate.persister.collection;
import java.io.Serializable;
-import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
-import java.sql.Types;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibern...
[truncated message content] |