HHH-7295 - ParentAuditing Test in Envers Testsuite fails across different databases with different error messages because Hibernate does not set LockMode correctly

This commit is contained in:
Steve Ebersole 2012-05-30 08:55:20 -05:00
parent 835f4452eb
commit 06f0a13ee3
1 changed files with 34 additions and 12 deletions

View File

@ -34,6 +34,7 @@ import org.hibernate.event.spi.EventType;
import org.hibernate.jdbc.ReturningWork; import org.hibernate.jdbc.ReturningWork;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
import org.hibernate.property.Getter; import org.hibernate.property.Getter;
import org.hibernate.sql.Update; import org.hibernate.sql.Update;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -96,40 +97,57 @@ public class ValidityAuditStrategy implements AuditStrategy {
session.save(auditedEntityName, data); session.save(auditedEntityName, data);
sessionCacheCleaner.scheduleAuditDataRemoval(session, data); sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
final Queryable productionEntityQueryable = (Queryable) sessionImplementor.getFactory().getEntityPersister( entityName ); final Queryable productionEntityQueryable = getQueryable( entityName, sessionImplementor );
final Queryable auditedEntityQueryable = (Queryable) sessionImplementor.getFactory().getEntityPersister( auditedEntityName ); final Queryable rootProductionEntityQueryable = getQueryable( productionEntityQueryable.getRootEntityName(), sessionImplementor );
final Queryable revisionInfoEntityQueryable = (Queryable) sessionImplementor.getFactory().getEntityPersister( revisionInfoEntityName ); final Queryable auditedEntityQueryable = getQueryable( auditedEntityName, sessionImplementor );
final Queryable rootAuditedEntityQueryable = getQueryable( auditedEntityQueryable.getRootEntityName(), sessionImplementor );
final Queryable revisionInfoEntityQueryable = getQueryable( revisionInfoEntityName, sessionImplementor );
final String updateTableName;
if ( UnionSubclassEntityPersister.class.isInstance( rootProductionEntityQueryable ) ) {
// this is the condition causing all the problems in terms of the generated SQL UPDATE
// the problem being that we currently try to update the in-line view made up of the union query
//
// this is extremely hacky means to get the root table name for the union subclass style entities.
// hacky because it relies on internal behavior of UnionSubclassEntityPersister
// !!!!!! NOTICE - using subclass persister, not root !!!!!!
updateTableName = auditedEntityQueryable.getSubclassTableName( 0 );
}
else {
updateTableName = rootAuditedEntityQueryable.getTableName();
}
// first we need to flush the session in order to have the new audit data inserted // first we need to flush the session in order to have the new audit data inserted
// todo: expose org.hibernate.internal.SessionImpl.autoFlushIfRequired via SessionImplementor // todo: expose org.hibernate.internal.SessionImpl.autoFlushIfRequired via SessionImplementor
// for now, we duplicate some of that logic here // for now, we duplicate some of that logic here
autoFlushIfRequired( sessionImplementor, auditedEntityQueryable, revisionInfoEntityQueryable ); autoFlushIfRequired( sessionImplementor, rootAuditedEntityQueryable, revisionInfoEntityQueryable );
final Type revisionInfoIdType = sessionImplementor.getFactory() final Type revisionInfoIdType = sessionImplementor.getFactory()
.getEntityPersister( revisionInfoEntityName ) .getEntityPersister( revisionInfoEntityName )
.getIdentifierType(); .getIdentifierType();
final String revEndColumnName = auditedEntityQueryable.toColumns( auditCfg.getAuditEntCfg().getRevisionEndFieldName() )[0]; final String revEndColumnName = rootAuditedEntityQueryable.toColumns( auditCfg.getAuditEntCfg().getRevisionEndFieldName() )[0];
final boolean isRevisionEndTimestampEnabled = auditCfg.getAuditEntCfg().isRevisionEndTimestampEnabled(); final boolean isRevisionEndTimestampEnabled = auditCfg.getAuditEntCfg().isRevisionEndTimestampEnabled();
// update audit_ent set REVEND = ? [, REVEND_TSTMP = ?] where (prod_ent_id) = ? and REV <> ? and REVEND is null // update audit_ent set REVEND = ? [, REVEND_TSTMP = ?] where (prod_ent_id) = ? and REV <> ? and REVEND is null
final Update update = new Update( dialect ).setTableName( auditedEntityQueryable.getTableName() ); final Update update = new Update( dialect ).setTableName( updateTableName );
// set REVEND = ? // set REVEND = ?
update.addColumn( revEndColumnName ); update.addColumn( revEndColumnName );
// set [, REVEND_TSTMP = ?] // set [, REVEND_TSTMP = ?]
if ( isRevisionEndTimestampEnabled ) { if ( isRevisionEndTimestampEnabled ) {
update.addColumn( update.addColumn(
auditedEntityQueryable.toColumns( rootAuditedEntityQueryable.toColumns(
auditCfg.getAuditEntCfg().getRevisionEndTimestampFieldName() auditCfg.getAuditEntCfg().getRevisionEndTimestampFieldName()
)[0] )[0]
); );
} }
// where (prod_ent_id) = ? // where (prod_ent_id) = ?
update.addPrimaryKeyColumns( productionEntityQueryable.getIdentifierColumnNames() ); update.addPrimaryKeyColumns( rootProductionEntityQueryable.getIdentifierColumnNames() );
// where REV <> ? // where REV <> ?
update.addWhereColumn( update.addWhereColumn(
auditedEntityQueryable.toColumns( rootAuditedEntityQueryable.toColumns(
auditCfg.getAuditEntCfg().getRevisionNumberPath() auditCfg.getAuditEntCfg().getRevisionNumberPath()
)[0], )[0],
"<> ?" "<> ?"
@ -158,7 +176,7 @@ public class ValidityAuditStrategy implements AuditStrategy {
if ( isRevisionEndTimestampEnabled ) { if ( isRevisionEndTimestampEnabled ) {
final Object revEndTimestampObj = revisionTimestampGetter.get( revision ); final Object revEndTimestampObj = revisionTimestampGetter.get( revision );
final Date revisionEndTimestamp = convertRevEndTimestampToDate( revEndTimestampObj ); final Date revisionEndTimestamp = convertRevEndTimestampToDate( revEndTimestampObj );
final Type revEndTsType = auditedEntityQueryable.getPropertyType( final Type revEndTsType = rootAuditedEntityQueryable.getPropertyType(
auditCfg.getAuditEntCfg().getRevisionEndTimestampFieldName() auditCfg.getAuditEntCfg().getRevisionEndTimestampFieldName()
); );
revEndTsType.nullSafeSet( preparedStatement, revisionEndTimestamp, index, sessionImplementor ); revEndTsType.nullSafeSet( preparedStatement, revisionEndTimestamp, index, sessionImplementor );
@ -166,12 +184,12 @@ public class ValidityAuditStrategy implements AuditStrategy {
} }
// where (prod_ent_id) = ? // where (prod_ent_id) = ?
final Type idType = productionEntityQueryable.getIdentifierType(); final Type idType = rootProductionEntityQueryable.getIdentifierType();
idType.nullSafeSet( preparedStatement, id, index, sessionImplementor ); idType.nullSafeSet( preparedStatement, id, index, sessionImplementor );
index += idType.getColumnSpan( sessionImplementor.getFactory() ); index += idType.getColumnSpan( sessionImplementor.getFactory() );
// where REV <> ? // where REV <> ?
final Type revType = auditedEntityQueryable.getPropertyType( final Type revType = rootAuditedEntityQueryable.getPropertyType(
auditCfg.getAuditEntCfg().getRevisionNumberPath() auditCfg.getAuditEntCfg().getRevisionNumberPath()
); );
revType.nullSafeSet( preparedStatement, revisionNumber, index, sessionImplementor ); revType.nullSafeSet( preparedStatement, revisionNumber, index, sessionImplementor );
@ -206,6 +224,10 @@ public class ValidityAuditStrategy implements AuditStrategy {
sessionCacheCleaner.scheduleAuditDataRemoval(session, data); sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
} }
private Queryable getQueryable(String entityName, SessionImplementor sessionImplementor) {
return (Queryable) sessionImplementor.getFactory().getEntityPersister( entityName );
}
private void autoFlushIfRequired( private void autoFlushIfRequired(
SessionImplementor sessionImplementor, SessionImplementor sessionImplementor,
Queryable auditedEntityQueryable, Queryable auditedEntityQueryable,