Update of /cvsroot/hibernate/Hibernate/cirrus/hibernate/persister
In directory usw-pr-cvs1:/tmp/cvs-serv30487/cirrus/hibernate/persister
Modified Files:
Tag: dynamic_update
AbstractEntityPersister.java ClassPersister.java
EntityPersister.java MultiTableEntityPersister.java
Log Message:
dynamically generated update and insert SQL to:
* update only columns that changed
* insert only non-null values
Index: AbstractEntityPersister.java
===================================================================
RCS file: /cvsroot/hibernate/Hibernate/cirrus/hibernate/persister/AbstractEntityPersister.java,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -C2 -d -r1.9 -r1.9.2.1
*** AbstractEntityPersister.java 26 Oct 2002 16:43:27 -0000 1.9
--- AbstractEntityPersister.java 31 Oct 2002 08:36:18 -0000 1.9.2.1
***************
*** 234,238 ****
* Determine if the given field values are dirty
*/
! public boolean isDirty(Object[] x, Object[] y, Object owner, SessionImplementor session) throws HibernateException {
int prop = TypeFactory.findDirty( propertyTypes, x, y, owner, session.getFactory() );
if ( prop==-1) {
--- 234,238 ----
* Determine if the given field values are dirty
*/
! public boolean isDirty(Object[] x, Object[] y, boolean[] dirtyFields, Object owner, SessionImplementor session) throws HibernateException {
int prop = TypeFactory.findDirty( propertyTypes, x, y, owner, session.getFactory() );
if ( prop==-1) {
***************
*** 241,244 ****
--- 241,246 ----
else {
if ( log.isTraceEnabled() ) log.trace( className + "."+ propertyNames[prop] + " is dirty" );
+ dirtyFields[prop] = true;
+ for ( int i=prop+1; i<hydrateSpan; i++ ) dirtyFields[i] = propertyTypes[i].isDirty( x[i], y[i], owner, session.getFactory() );
return true;
}
Index: ClassPersister.java
===================================================================
RCS file: /cvsroot/hibernate/Hibernate/cirrus/hibernate/persister/ClassPersister.java,v
retrieving revision 1.18
retrieving revision 1.18.2.1
diff -C2 -d -r1.18 -r1.18.2.1
*** ClassPersister.java 25 Oct 2002 18:26:11 -0000 1.18
--- ClassPersister.java 31 Oct 2002 08:36:18 -0000 1.18.2.1
***************
*** 141,145 ****
* Compare two snapshots of the state of an instance to determine if the persistent state was modified
*/
! public boolean isDirty(Object[] x, Object[] y, Object owner, SessionImplementor session) throws HibernateException;
/**
--- 141,145 ----
* Compare two snapshots of the state of an instance to determine if the persistent state was modified
*/
! public boolean isDirty(Object[] x, Object[] y, boolean[] dirtyFields, Object owner, SessionImplementor session) throws HibernateException;
/**
***************
*** 221,225 ****
* Update a persistent instance
*/
! public void update(Serializable id, Object[] fields, Object oldVersion, Object object, SessionImplementor session) throws SQLException, HibernateException;
/**
--- 221,225 ----
* Update a persistent instance
*/
! public void update(Serializable id, Object[] fields, boolean[] dirty, Object oldVersion, Object object, SessionImplementor session) throws SQLException, HibernateException;
/**
Index: EntityPersister.java
===================================================================
RCS file: /cvsroot/hibernate/Hibernate/cirrus/hibernate/persister/EntityPersister.java,v
retrieving revision 1.32
retrieving revision 1.32.2.1
diff -C2 -d -r1.32 -r1.32.2.1
*** EntityPersister.java 27 Oct 2002 03:11:33 -0000 1.32
--- EntityPersister.java 31 Oct 2002 08:36:18 -0000 1.32.2.1
***************
*** 24,27 ****
--- 24,28 ----
import java.sql.SQLException;
import java.util.ArrayList;
+ import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
***************
*** 65,70 ****
--- 66,73 ----
private transient final String identityInsertString;
private transient final String identitySelectString;
+ private transient final String identityColumnInsertString;
private transient final String[] identifierColumnNames;
+ private transient final int identifierColumnSpan;
private transient final Cascades.IdentifierValue unsavedIdentifierValue;
***************
*** 302,310 ****
* Generate the SQL that inserts a row
*/
! protected String generateInsertString(boolean identityString, String identityColumnInsertString) {
- boolean hasPropertyColumns = columnNames.length > 0;
boolean insertIdentifierColumns = !identityString || identityColumnInsertString!=null;
! String commaAfterProperties = hasPropertyColumns && ( insertIdentifierColumns || isPolymorphic() ) ? ", " : "";
String commaAfterIdentifiers = insertIdentifierColumns && isPolymorphic() ? ", " : "";
--- 305,327 ----
* Generate the SQL that inserts a row
*/
! protected String generateInsertString(boolean identityString, String identityColumnInsertString, boolean[] notNullProps) {
boolean insertIdentifierColumns = !identityString || identityColumnInsertString!=null;
!
! StringBuffer setters = new StringBuffer(50);
! int cols = 0;
! for ( int i=0; i<hydrateSpan; i++) {
! if ( notNullProps[i] ) {
! int len = propertyColumnNames[i].length;
! if (len>0) {
! if (cols>0) setters.append(", ");
! setters.append( StringHelper.join( ", ", propertyColumnNames[i] ) );
! cols += len;
! }
! }
! }
!
! boolean hasPropertyColumns = cols>0;
! String commaAfterProperties = hasPropertyColumns && ( insertIdentifierColumns || isPolymorphic() ) ? ", " : "";
String commaAfterIdentifiers = insertIdentifierColumns && isPolymorphic() ? ", " : "";
***************
*** 312,327 ****
.append(qualifiedTableName)
.append(" ( ")
! .append( cirrus.hibernate.helpers.StringHelper.join( ", ", columnNames ) )
! .append(commaAfterProperties)
! .append( insertIdentifierColumns ? StringHelper.join( ", ", identifierColumnNames ) : "" )
! .append(commaAfterIdentifiers)
! .append( isPolymorphic() ? getDiscriminatorColumnName() : "" ) //to handle discriminator column
! .append(" ) values ( ")
! .append( hasPropertyColumns ? StringHelper.repeat( "?, ", columnNames.length-1 ) : "" )
! .append( hasPropertyColumns ? "?" : "" )
.append(commaAfterProperties);
if ( !identityString ) {
! buf.append( StringHelper.repeat( "?, ", identifierColumnNames.length-1 ) )
! .append( identifierColumnNames.length > 0 ? "?" : "" );
}
else if ( identityColumnInsertString!=null ) {
--- 329,347 ----
.append(qualifiedTableName)
.append(" ( ")
! .append( setters.toString() )
.append(commaAfterProperties);
+ if (insertIdentifierColumns) buf.append( StringHelper.join( ", ", identifierColumnNames ) );
+ buf.append(commaAfterIdentifiers);
+ if ( isPolymorphic() ) buf.append( getDiscriminatorColumnName() );
+
+ buf.append(" ) values ( ");
+ if (hasPropertyColumns) {
+ buf.append( StringHelper.repeat( "?, ", cols-1 ) )
+ .append("?");
+ buf.append(commaAfterProperties);
+ }
if ( !identityString ) {
! buf.append( StringHelper.repeat( "?, ", identifierColumnNames.length-1 ) );
! /*if (identifierColumnNames.length > 0) */buf.append("?");
}
else if ( identityColumnInsertString!=null ) {
***************
*** 329,333 ****
}
buf.append(commaAfterIdentifiers);
! if ( isPolymorphic() ) buf.append(discriminatorSQLString); //to handle discriminator column
return buf.append(" )").toString();
}
--- 349,353 ----
}
buf.append(commaAfterIdentifiers);
! if ( isPolymorphic() ) buf.append(discriminatorSQLString);
return buf.append(" )").toString();
}
***************
*** 368,377 ****
* Generate the SQL that updates a row by id (and version)
*/
! protected String generateUpdateString() {
! StringBuffer setters = new StringBuffer(20);
! for (int i=0; i<columnNames.length; i++) {
! setters.append( columnNames[i] ).append(" = ?");
! if (i!=columnNames.length-1) setters.append(", ");
}
StringBuffer buf = new StringBuffer(100)
.append("update ")
--- 388,407 ----
* Generate the SQL that updates a row by id (and version)
*/
! protected String generateUpdateString( boolean[] dirtyProps ) {
! //String setters = StringHelper.join(" = ?, ", columnNames);
! //if (columnNames.length!=0) setters = setters + " = ?"
! StringBuffer setters = new StringBuffer(50);
! boolean cols = false;
! for ( int i=0; i<dirtyProps.length; i++ ) {
! if ( dirtyProps[i] ) {
! if ( propertyColumnNames[i].length > 0 ) {
! if (cols) setters.append(", ");
! cols = true;
! setters.append( StringHelper.join(" = ?, ", propertyColumnNames[i] ) )
! .append(" = ?");
! }
! }
}
+
StringBuffer buf = new StringBuffer(100)
.append("update ")
***************
*** 413,417 ****
* Marshall the fields of a persistent instance to a prepared statement
*/
! protected void dehydrate(Serializable id, Object[] fields, PreparedStatement st, SessionImplementor session) throws SQLException, HibernateException {
if ( log.isTraceEnabled() ) log.trace("Dehydrating entity: " + getClassName() + '#' + id);
--- 443,447 ----
* Marshall the fields of a persistent instance to a prepared statement
*/
! protected int dehydrate(Serializable id, boolean[] dirty, Object[] fields, PreparedStatement st, SessionImplementor session) throws SQLException, HibernateException {
if ( log.isTraceEnabled() ) log.trace("Dehydrating entity: " + getClassName() + '#' + id);
***************
*** 419,428 ****
int index = 1;
for (int j=0; j<hydrateSpan; j++) {
! getPropertyTypes()[j].nullSafeSet( st, fields[j], index, session );
! index += propertyColumnSpans[j];
}
! if ( id!=null ) getIdentifierType().nullSafeSet( st, id, index, session );
!
}
--- 449,465 ----
int index = 1;
for (int j=0; j<hydrateSpan; j++) {
! if ( dirty[j] ) {
! getPropertyTypes()[j].nullSafeSet( st, fields[j], index, session );
! index += propertyColumnSpans[j];
! }
}
! if ( id!=null ) {
! getIdentifierType().nullSafeSet( st, id, index, session );
! index += identifierColumnSpan;
! }
!
! return index;
!
}
***************
*** 479,482 ****
--- 516,525 ----
}
+ private boolean[] notNull(Object[] fields) {
+ boolean[] notNull = new boolean[hydrateSpan];
+ for ( int i=0; i<hydrateSpan; i++ ) notNull[i] = fields[i]!=null;
+ return notNull;
+ }
+
/**
* Persist an object
***************
*** 488,494 ****
if ( isVersioned() ) log.trace( "Version: " + Versioning.getVersion(fields, this) );
}
!
// Render the SQL query
! PreparedStatement statement = session.getBatcher().prepareBatchStatement( sqlInsert() );
try {
--- 531,541 ----
if ( isVersioned() ) log.trace( "Version: " + Versioning.getVersion(fields, this) );
}
!
! boolean[] notNull = notNull(fields);
!
// Render the SQL query
! PreparedStatement statement = session.getBatcher().prepareBatchStatement(
! generateInsertString(false, null, notNull)
! ); //sqlInsert()
try {
***************
*** 497,501 ****
// insert was issued (cos of foreign key constraints). Not necessarily the object's current state
! dehydrate(id, fields, statement, session);
session.getBatcher().addToBatch(1);
--- 544,548 ----
// insert was issued (cos of foreign key constraints). Not necessarily the object's current state
! dehydrate(id, notNull, fields, statement, session);
session.getBatcher().addToBatch(1);
***************
*** 507,511 ****
throw sqle;
}
!
}
--- 554,558 ----
throw sqle;
}
!
}
***************
*** 519,529 ****
if ( isVersioned() ) log.trace( "Version: " + Versioning.getVersion(fields, this) );
}
// Render the SQL query
! PreparedStatement statement = session.getBatcher().prepareStatement( sqlIdentityInsert() );
try {
! dehydrate(null, fields, statement, session);
statement.executeUpdate();
--- 566,580 ----
if ( isVersioned() ) log.trace( "Version: " + Versioning.getVersion(fields, this) );
}
+
+ boolean[] notNull = notNull(fields);
// Render the SQL query
! PreparedStatement statement = session.getBatcher().prepareStatement(
! generateInsertString(true, identityColumnInsertString, notNull)
! ); //sqlIdentityInsert()
try {
! dehydrate(null, notNull, fields, statement, session);
statement.executeUpdate();
***************
*** 616,620 ****
* Update an object
*/
! public void update(Serializable id, Object[] fields, Object oldVersion, Object object, SessionImplementor session) throws SQLException, HibernateException {
if ( log.isTraceEnabled() ) {
--- 667,671 ----
* Update an object
*/
! public void update(Serializable id, Object[] fields, boolean[] dirty, Object oldVersion, Object object, SessionImplementor session) throws SQLException, HibernateException {
if ( log.isTraceEnabled() ) {
***************
*** 623,630 ****
}
! if (!hasColumns) return;
//Render the SQL query
! String sql = sqlUpdate();
final PreparedStatement statement;
if ( isVersioned() ) {
--- 674,683 ----
}
! if (!hasColumns) return; //TODO: fix this somehow - I think its only needed for use with update()
!
! if ( isVersioned() ) dirty[ getVersionProperty() ] = true;
//Render the SQL query
! String sql = generateUpdateString(dirty); //sqlUpdate()
final PreparedStatement statement;
if ( isVersioned() ) {
***************
*** 639,646 ****
//Now write the values of fields onto the prepared statement
! dehydrate(id, fields, statement, session);
if ( isVersioned() ) {
! getVersionType().nullSafeSet( statement, oldVersion, columnNames.length + identifierColumnNames.length + 1, session );
check( statement.executeUpdate(), id );
}
--- 692,699 ----
//Now write the values of fields onto the prepared statement
! int versionIndex = dehydrate(id, dirty, fields, statement, session);
if ( isVersioned() ) {
! getVersionType().nullSafeSet( statement, oldVersion, versionIndex, session );
check( statement.executeUpdate(), id );
}
***************
*** 676,681 ****
// IDENTIFIER
! int idColumnSpan = model.getIdentifier().getColumnSpan();
! identifierColumnNames = new String[idColumnSpan];
Value idValue = model.getIdentifier();
--- 729,734 ----
// IDENTIFIER
! identifierColumnSpan = model.getIdentifier().getColumnSpan();
! identifierColumnNames = new String[identifierColumnSpan];
Value idValue = model.getIdentifier();
***************
*** 716,720 ****
! final String identityColumnInsertString;
IdentifierGenerator idgen = model.getIdentifier().getIdentifierGenerator();
useIdentityColumn = dialect.supportsIdentityColumns() && ( idgen instanceof NativeGenerator );
--- 769,773 ----
! //final String identityColumnInsertString;
IdentifierGenerator idgen = model.getIdentifier().getIdentifierGenerator();
useIdentityColumn = dialect.supportsIdentityColumns() && ( idgen instanceof NativeGenerator );
***************
*** 848,855 ****
while ( iter.hasNext() ) joinedFetch[j++] = ( (Integer) iter.next() ).intValue();
deleteString = generateDeleteString();
! insertString = generateInsertString(false, null);
! identityInsertString = useIdentityColumn ? generateInsertString(true, identityColumnInsertString) : null;
! updateString = generateUpdateString();
String lockString = generateLockString();
--- 901,911 ----
while ( iter.hasNext() ) joinedFetch[j++] = ( (Integer) iter.next() ).intValue();
+ boolean[] allProps = new boolean[hydrateSpan];
+ Arrays.fill(allProps, true);
+
deleteString = generateDeleteString();
! insertString = generateInsertString(false, null, allProps);
! identityInsertString = useIdentityColumn ? generateInsertString(true, identityColumnInsertString, allProps): null;
! updateString = generateUpdateString(allProps);
String lockString = generateLockString();
Index: MultiTableEntityPersister.java
===================================================================
RCS file: /cvsroot/hibernate/Hibernate/cirrus/hibernate/persister/MultiTableEntityPersister.java,v
retrieving revision 1.23
retrieving revision 1.23.2.1
diff -C2 -d -r1.23 -r1.23.2.1
*** MultiTableEntityPersister.java 27 Oct 2002 03:11:33 -0000 1.23
--- MultiTableEntityPersister.java 31 Oct 2002 08:36:18 -0000 1.23.2.1
***************
*** 686,690 ****
* Update an object
*/
! public void update(Serializable id, Object[] fields, Object oldVersion, Object object, SessionImplementor session) throws SQLException, HibernateException {
if ( log.isTraceEnabled() ) {
--- 686,690 ----
* Update an object
*/
! public void update(Serializable id, Object[] fields, boolean[] dirty, Object oldVersion, Object object, SessionImplementor session) throws SQLException, HibernateException {
if ( log.isTraceEnabled() ) {
|