From 9a2948d047dd1d961fcde3cb7c9fd1b4874f8f03 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Sat, 6 Oct 2007 01:52:08 +0000 Subject: [PATCH] HHH-1593 - StackOverflow when calling configuration.setListener(null) git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@14065 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- etc/log4j.properties | 4 +- src/org/hibernate/cfg/Configuration.java | 44 ++- src/org/hibernate/cfg/HbmBinder.java | 17 +- .../hibernate/criterion/DetachedCriteria.java | 32 +- src/org/hibernate/dialect/DialectFactory.java | 18 +- src/org/hibernate/dialect/HSQLDialect.java | 22 +- src/org/hibernate/dialect/MySQLDialect.java | 2 +- src/org/hibernate/dialect/SAPDBDialect.java | 12 +- .../engine/loading/CollectionLoadContext.java | 2 +- .../engine/loading/LoadContexts.java | 17 +- .../def/DefaultFlushEntityEventListener.java | 8 +- .../hibernate/hql/ast/tree/FromClause.java | 7 +- .../id/IdentifierGeneratorFactory.java | 149 +++++---- src/org/hibernate/impl/IteratorImpl.java | 49 ++- src/org/hibernate/mapping/Table.java | 9 +- src/org/hibernate/sql/Template.java | 2 + .../tool/hbm2ddl/DatabaseMetadata.java | 2 +- .../junit/functional/FunctionalTestCase.java | 25 +- test/org/hibernate/test/AllTests.java | 2 + test/org/hibernate/test/cfg/ListenerTest.java | 313 ++++++++++++++++++ .../hibernate/test/filter/Category.hbm.xml | 27 +- .../test/filter/DynamicFilterTest.java | 7 + test/org/hibernate/test/filter/defs.hbm.xml | 4 + .../test/jpa/ql/JPAQLComplianceTest.java | 6 + .../test/legacy/MasterDetailTest.java | 9 +- .../reattachment/ProxyReattachmentTest.java | 151 +++++++++ 26 files changed, 769 insertions(+), 171 deletions(-) create mode 100644 test/org/hibernate/test/cfg/ListenerTest.java diff --git a/etc/log4j.properties b/etc/log4j.properties index 1922c1667a..56066bde42 100644 --- a/etc/log4j.properties +++ b/etc/log4j.properties @@ -14,8 +14,8 @@ log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n log4j.rootLogger=warn, stdout -#log4j.logger.org.hibernate=info -log4j.logger.org.hibernate=debug +log4j.logger.org.hibernate=info +#log4j.logger.org.hibernate=debug ### log HQL query parser activity #log4j.logger.org.hibernate.hql.ast.AST=debug diff --git a/src/org/hibernate/cfg/Configuration.java b/src/org/hibernate/cfg/Configuration.java index 82b57db43b..7f4ab15761 100644 --- a/src/org/hibernate/cfg/Configuration.java +++ b/src/org/hibernate/cfg/Configuration.java @@ -1653,31 +1653,41 @@ public class Configuration implements Serializable { setListeners( type, new String[]{impl} ); } + public void setListener(String type, String listener) { + String[] listeners = null; + if ( listener != null ) { + listeners = (String[]) Array.newInstance( String.class, 1 ); + listeners[0] = listener; + } + setListeners( type, listeners ); + } + public void setListeners(String type, String[] listenerClasses) { - Object[] listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), listenerClasses.length ); - for ( int i = 0; i < listeners.length ; i++ ) { - try { - listeners[i] = ReflectHelper.classForName( listenerClasses[i] ).newInstance(); - } - catch (Exception e) { - throw new MappingException( - "Unable to instantiate specified event (" + type + ") listener class: " + listenerClasses[i], - e - ); + Object[] listeners = null; + if ( listenerClasses != null ) { + listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), listenerClasses.length ); + for ( int i = 0; i < listeners.length ; i++ ) { + try { + listeners[i] = ReflectHelper.classForName( listenerClasses[i] ).newInstance(); + } + catch (Exception e) { + throw new MappingException( + "Unable to instantiate specified event (" + type + ") listener class: " + listenerClasses[i], + e + ); + } } } setListeners( type, listeners ); } public void setListener(String type, Object listener) { - if ( listener == null ) { - setListener( type, null ); - } - else { - Object[] listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), 1 ); + Object[] listeners = null; + if ( listener != null ) { + listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), 1 ); listeners[0] = listener; - setListeners( type, listeners ); } + setListeners( type, listeners ); } public void setListeners(String type, Object[] listeners) { @@ -1916,7 +1926,7 @@ public class Configuration implements Serializable { } } else { - log.warn( "Unrecognized listener type [" + type + "]" ); + throw new MappingException("Unrecognized listener type [" + type + "]"); } } diff --git a/src/org/hibernate/cfg/HbmBinder.java b/src/org/hibernate/cfg/HbmBinder.java index 6ce93a63ea..8b1e347a4e 100644 --- a/src/org/hibernate/cfg/HbmBinder.java +++ b/src/org/hibernate/cfg/HbmBinder.java @@ -633,10 +633,7 @@ public final class HbmBinder { // PERSISTER Attribute persisterNode = node.attribute( "persister" ); - if ( persisterNode == null ) { - // persister = SingleTableEntityPersister.class; - } - else { + if ( persisterNode != null ) { try { entity.setEntityPersisterClass( ReflectHelper.classForName( persisterNode .getValue() ) ); @@ -1567,9 +1564,9 @@ public final class HbmBinder { } private static void validateCascade(Element node, String path) { - String cascade = node.attributeValue("cascade"); - if ( cascade!=null && cascade.indexOf("delete-orphan")>0 ) { - throw new MappingException("single-valued associations do not support orphan delete: " + path); + String cascade = node.attributeValue( "cascade" ); + if ( cascade != null && cascade.indexOf( "delete-orphan" ) >= 0 ) { + throw new MappingException( "single-valued associations do not support orphan delete: " + path ); } } @@ -2250,7 +2247,7 @@ public final class HbmBinder { String entityName = ( (OneToMany) list.getElement() ).getReferencedEntityName(); PersistentClass referenced = mappings.getClass( entityName ); IndexBackref ib = new IndexBackref(); - ib.setName( '_' + node.attributeValue( "name" ) + "IndexBackref" ); + ib.setName( '_' + list.getOwnerEntityName() + "." + node.attributeValue( "name" ) + "IndexBackref" ); ib.setUpdateable( false ); ib.setSelectable( false ); ib.setCollectionRole( list.getRole() ); @@ -2353,7 +2350,7 @@ public final class HbmBinder { String entityName = ( (OneToMany) map.getElement() ).getReferencedEntityName(); PersistentClass referenced = mappings.getClass( entityName ); IndexBackref ib = new IndexBackref(); - ib.setName( '_' + node.attributeValue( "name" ) + "IndexBackref" ); + ib.setName( '_' + map.getOwnerEntityName() + "." + node.attributeValue( "name" ) + "IndexBackref" ); ib.setUpdateable( false ); ib.setSelectable( false ); ib.setCollectionRole( map.getRole() ); @@ -2486,7 +2483,7 @@ public final class HbmBinder { String entityName = ( (OneToMany) collection.getElement() ).getReferencedEntityName(); PersistentClass referenced = mappings.getClass( entityName ); Backref prop = new Backref(); - prop.setName( '_' + node.attributeValue( "name" ) + "Backref" ); + prop.setName( '_' + collection.getOwnerEntityName() + "." + node.attributeValue( "name" ) + "Backref" ); prop.setUpdateable( false ); prop.setSelectable( false ); prop.setCollectionRole( collection.getRole() ); diff --git a/src/org/hibernate/criterion/DetachedCriteria.java b/src/org/hibernate/criterion/DetachedCriteria.java index 53d731bf86..8de357c57f 100755 --- a/src/org/hibernate/criterion/DetachedCriteria.java +++ b/src/org/hibernate/criterion/DetachedCriteria.java @@ -6,10 +6,10 @@ import java.io.Serializable; import org.hibernate.Criteria; import org.hibernate.FetchMode; import org.hibernate.HibernateException; +import org.hibernate.LockMode; import org.hibernate.Session; import org.hibernate.engine.SessionImplementor; import org.hibernate.impl.CriteriaImpl; -import org.hibernate.impl.SessionImpl; import org.hibernate.transform.ResultTransformer; /** @@ -87,7 +87,7 @@ public class DetachedCriteria implements CriteriaSpecification, Serializable { public DetachedCriteria createCriteria(String associationPath, String alias) throws HibernateException { - return new DetachedCriteria( impl, criteria.createCriteria(associationPath) ); + return new DetachedCriteria( impl, criteria.createCriteria(associationPath, alias) ); } public DetachedCriteria createCriteria(String associationPath) @@ -122,4 +122,32 @@ public class DetachedCriteria implements CriteriaSpecification, Serializable { CriteriaImpl getCriteriaImpl() { return impl; } + + public DetachedCriteria createAlias(String associationPath, String alias, int joinType) throws HibernateException { + criteria.createAlias(associationPath, alias, joinType); + return this; + } + + public DetachedCriteria createCriteria(String associationPath, int joinType) throws HibernateException { + return new DetachedCriteria(impl, criteria.createCriteria(associationPath, joinType)); + } + + public DetachedCriteria createCriteria(String associationPath, String alias, int joinType) throws HibernateException { + return new DetachedCriteria(impl, criteria.createCriteria(associationPath, alias, joinType)); + } + + public DetachedCriteria setComment(String comment) { + criteria.setComment(comment); + return this; + } + + public DetachedCriteria setLockMode(LockMode lockMode) { + criteria.setLockMode(lockMode); + return this; + } + + public DetachedCriteria setLockMode(String alias, LockMode lockMode) { + criteria.setLockMode(alias, lockMode); + return this; + } } diff --git a/src/org/hibernate/dialect/DialectFactory.java b/src/org/hibernate/dialect/DialectFactory.java index a79da427d0..5f91650687 100644 --- a/src/org/hibernate/dialect/DialectFactory.java +++ b/src/org/hibernate/dialect/DialectFactory.java @@ -109,20 +109,30 @@ public class DialectFactory { } } + // TODO : this is the stuff it'd be nice to move to a properties file or some other easily user-editable place private static final Map MAPPERS = new HashMap(); static { - // TODO : this is the stuff it'd be nice to move to a properties file or some other easily user-editable place MAPPERS.put( "HSQL Database Engine", new VersionInsensitiveMapper( "org.hibernate.dialect.HSQLDialect" ) ); - MAPPERS.put( "DB2/NT", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); - MAPPERS.put( "DB2/LINUX", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "H2", new VersionInsensitiveMapper( "org.hibernate.dialect.H2Dialect" ) ); MAPPERS.put( "MySQL", new VersionInsensitiveMapper( "org.hibernate.dialect.MySQLDialect" ) ); MAPPERS.put( "PostgreSQL", new VersionInsensitiveMapper( "org.hibernate.dialect.PostgreSQLDialect" ) ); + MAPPERS.put( "Apache Derby", new VersionInsensitiveMapper( "org.hibernate.dialect.DerbyDialect" ) ); + MAPPERS.put( "Microsoft SQL Server Database", new VersionInsensitiveMapper( "org.hibernate.dialect.SQLServerDialect" ) ); MAPPERS.put( "Microsoft SQL Server", new VersionInsensitiveMapper( "org.hibernate.dialect.SQLServerDialect" ) ); MAPPERS.put( "Sybase SQL Server", new VersionInsensitiveMapper( "org.hibernate.dialect.SybaseDialect" ) ); MAPPERS.put( "Adaptive Server Enterprise", new VersionInsensitiveMapper( "org.hibernate.dialect.SybaseDialect" ) ); + MAPPERS.put( "Informix Dynamic Server", new VersionInsensitiveMapper( "org.hibernate.dialect.InformixDialect" ) ); - MAPPERS.put( "Apache Derby", new VersionInsensitiveMapper( "org.hibernate.dialect.DerbyDialect" ) ); + + // thanks goodness for "universal" databases... + MAPPERS.put( "DB2/NT", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "DB2/LINUX", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "DB2/6000", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "DB2/HPUX", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "DB2/SUN", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "DB2/LINUX390", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); + MAPPERS.put( "DB2/AIX64", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) ); MAPPERS.put( "Oracle", diff --git a/src/org/hibernate/dialect/HSQLDialect.java b/src/org/hibernate/dialect/HSQLDialect.java index 860ecd74fc..b212c51767 100644 --- a/src/org/hibernate/dialect/HSQLDialect.java +++ b/src/org/hibernate/dialect/HSQLDialect.java @@ -9,7 +9,6 @@ import org.hibernate.Hibernate; import org.hibernate.LockMode; import org.hibernate.StaleObjectStateException; import org.hibernate.JDBCException; -import org.hibernate.MappingException; import org.hibernate.engine.SessionImplementor; import org.hibernate.persister.entity.Lockable; import org.hibernate.util.ReflectHelper; @@ -203,23 +202,12 @@ public class HSQLDialect extends Dialect { return true; } - public String[] getCreateSequenceStrings(String sequenceName) { - return getCreateSequenceStrings( sequenceName, 1, 1 ); + protected String getCreateSequenceString(String sequenceName) { + return "create sequence " + sequenceName; } - public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) { - return new String[] { - "create table dual_" + sequenceName + " (zero integer)", - "insert into dual_" + sequenceName + " values (0)", - "create sequence " + sequenceName + " start with " + initialValue + " increment by " + incrementSize - }; - } - - public String[] getDropSequenceStrings(String sequenceName) { - return new String[] { - "drop table dual_" + sequenceName + " if exists", - "drop sequence " + sequenceName - }; + protected String getDropSequenceString(String sequenceName) { + return "drop sequence " + sequenceName; } public String getSelectSequenceNextValString(String sequenceName) { @@ -227,7 +215,7 @@ public class HSQLDialect extends Dialect { } public String getSequenceNextValString(String sequenceName) { - return "select next value for " + sequenceName + " from dual_" + sequenceName; + return "call next value for " + sequenceName; } public String getQuerySequencesString() { diff --git a/src/org/hibernate/dialect/MySQLDialect.java b/src/org/hibernate/dialect/MySQLDialect.java index 6f9006333e..f89a429fd8 100644 --- a/src/org/hibernate/dialect/MySQLDialect.java +++ b/src/org/hibernate/dialect/MySQLDialect.java @@ -36,7 +36,7 @@ public class MySQLDialect extends Dialect { registerColumnType( Types.VARBINARY, 16777215, "mediumblob" ); registerColumnType( Types.VARBINARY, 65535, "blob" ); registerColumnType( Types.VARBINARY, 255, "tinyblob" ); - registerColumnType( Types.NUMERIC, "numeric($p,$s)" ); + registerColumnType( Types.NUMERIC, "decimal($p,$s)" ); registerColumnType( Types.BLOB, "longblob" ); registerColumnType( Types.BLOB, 16777215, "mediumblob" ); registerColumnType( Types.BLOB, 65535, "blob" ); diff --git a/src/org/hibernate/dialect/SAPDBDialect.java b/src/org/hibernate/dialect/SAPDBDialect.java index 2c6ad49145..bbaab52616 100644 --- a/src/org/hibernate/dialect/SAPDBDialect.java +++ b/src/org/hibernate/dialect/SAPDBDialect.java @@ -7,12 +7,13 @@ import java.sql.Types; import org.hibernate.Hibernate; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; +import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; import org.hibernate.sql.CaseFragment; import org.hibernate.sql.DecodeCaseFragment; -import org.hibernate.sql.OracleJoinFragment; import org.hibernate.sql.JoinFragment; +import org.hibernate.sql.OracleJoinFragment; import org.hibernate.util.StringHelper; /** @@ -74,6 +75,15 @@ public class SAPDBDialect extends Dialect { registerFunction("date", new StandardSQLFunction("date", Hibernate.DATE) ); registerFunction("microsecond", new StandardSQLFunction("microsecond", Hibernate.INTEGER) ); + registerFunction( "second", new SQLFunctionTemplate(Hibernate.INTEGER, "second(?1)") ); + registerFunction( "minute", new SQLFunctionTemplate(Hibernate.INTEGER, "minute(?1)") ); + registerFunction( "hour", new SQLFunctionTemplate(Hibernate.INTEGER, "hour(?1)") ); + registerFunction( "day", new SQLFunctionTemplate(Hibernate.INTEGER, "day(?1)") ); + registerFunction( "month", new SQLFunctionTemplate(Hibernate.INTEGER, "month(?1)") ); + registerFunction( "year", new SQLFunctionTemplate(Hibernate.INTEGER, "year(?1)") ); + + registerFunction( "extract", new SQLFunctionTemplate(Hibernate.INTEGER, "?1(?3)") ); + registerFunction("dayname", new StandardSQLFunction("dayname", Hibernate.STRING) ); registerFunction("monthname", new StandardSQLFunction("monthname", Hibernate.STRING) ); registerFunction("dayofmonth", new StandardSQLFunction("dayofmonth", Hibernate.INTEGER) ); diff --git a/src/org/hibernate/engine/loading/CollectionLoadContext.java b/src/org/hibernate/engine/loading/CollectionLoadContext.java index 4e1dd59b17..e60d9d4c6c 100644 --- a/src/org/hibernate/engine/loading/CollectionLoadContext.java +++ b/src/org/hibernate/engine/loading/CollectionLoadContext.java @@ -153,7 +153,7 @@ public class CollectionLoadContext { public void endLoadingCollections(CollectionPersister persister) { SessionImplementor session = getLoadContext().getPersistenceContext().getSession(); if ( !loadContexts.hasLoadingCollectionEntries() - || localLoadingCollectionKeys.isEmpty() ) { + && localLoadingCollectionKeys.isEmpty() ) { return; } diff --git a/src/org/hibernate/engine/loading/LoadContexts.java b/src/org/hibernate/engine/loading/LoadContexts.java index c78c6440e7..4fbb3c8689 100644 --- a/src/org/hibernate/engine/loading/LoadContexts.java +++ b/src/org/hibernate/engine/loading/LoadContexts.java @@ -132,6 +132,17 @@ public class LoadContexts { * false otherwise. */ public boolean hasLoadingCollectionEntries() { + return ( collectionLoadContexts != null && !collectionLoadContexts.isEmpty() ); + } + + /** + * Do we currently have any registered internal entries corresponding to loading + * collections? + * + * @return True if we currently hold state pertaining to a registered loading collections; + * false otherwise. + */ + public boolean hasRegisteredLoadingCollectionEntries() { return ( xrefLoadingCollectionEntries != null && !xrefLoadingCollectionEntries.isEmpty() ); } @@ -228,7 +239,7 @@ public class LoadContexts { * @param key The key of the collection we are done processing. */ void unregisterLoadingCollectionXRef(CollectionKey key) { - if ( !hasLoadingCollectionEntries() ) { + if ( !hasRegisteredLoadingCollectionEntries() ) { return; } xrefLoadingCollectionEntries.remove(key); @@ -260,10 +271,10 @@ public class LoadContexts { LoadingCollectionEntry rtn = ( LoadingCollectionEntry ) xrefLoadingCollectionEntries.get( key ); if ( log.isTraceEnabled() ) { if ( rtn == null ) { - log.trace( "collection [" + key + "] located in load context" ); + log.trace( "collection [" + key + "] not located in load context" ); } else { - log.trace( "collection [" + key + "] not located in load context" ); + log.trace( "collection [" + key + "] located in load context" ); } } return rtn; diff --git a/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java b/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java index 78ce5ddf49..a59f36225a 100755 --- a/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java +++ b/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java @@ -68,12 +68,12 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener private void checkNaturalId( EntityPersister persister, - Serializable identifier, + EntityEntry entry, Object[] current, Object[] loaded, EntityMode entityMode, SessionImplementor session) { - if ( persister.hasNaturalIdentifier() ) { + if ( persister.hasNaturalIdentifier() && entry.getStatus() != Status.READ_ONLY ) { Object[] snapshot = null; Type[] types = persister.getPropertyTypes(); int[] props = persister.getNaturalIdentifierProperties(); @@ -84,7 +84,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener Object loadedVal; if ( loaded == null ) { if ( snapshot == null) { - snapshot = session.getPersistenceContext().getNaturalIdSnapshot( identifier, persister ); + snapshot = session.getPersistenceContext().getNaturalIdSnapshot( entry.getId(), persister ); } loadedVal = snapshot[i]; } else { @@ -166,7 +166,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener // grab its current state values = persister.getPropertyValues( entity, entityMode ); - checkNaturalId( persister, entry.getId(), values, loadedState, entityMode, session ); + checkNaturalId( persister, entry, values, loadedState, entityMode, session ); } return values; } diff --git a/src/org/hibernate/hql/ast/tree/FromClause.java b/src/org/hibernate/hql/ast/tree/FromClause.java index 9722ec4cda..66b803e926 100644 --- a/src/org/hibernate/hql/ast/tree/FromClause.java +++ b/src/org/hibernate/hql/ast/tree/FromClause.java @@ -85,13 +85,14 @@ public class FromClause extends HqlSqlWalkerNode implements HqlSqlTokenTypes, Di } void addDuplicateAlias(String alias, FromElement element) { - fromElementByClassAlias.put( alias, element ); + if ( alias != null ) { + fromElementByClassAlias.put( alias, element ); + } } private void checkForDuplicateClassAlias(String classAlias) throws SemanticException { if ( classAlias != null && fromElementByClassAlias.containsKey( classAlias ) ) { - throw new SemanticException( "Duplicate definition of alias '" - + classAlias + "'" ); + throw new SemanticException( "Duplicate definition of alias '" + classAlias + "'" ); } } diff --git a/src/org/hibernate/id/IdentifierGeneratorFactory.java b/src/org/hibernate/id/IdentifierGeneratorFactory.java index 071ff04f0b..c259dfd8f1 100644 --- a/src/org/hibernate/id/IdentifierGeneratorFactory.java +++ b/src/org/hibernate/id/IdentifierGeneratorFactory.java @@ -9,6 +9,7 @@ import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.dialect.Dialect; @@ -21,111 +22,133 @@ import org.hibernate.util.ReflectHelper; * @author Gavin King */ public final class IdentifierGeneratorFactory { - - private static final Log log = LogFactory.getLog(IdentifierGeneratorFactory.class); + + private static final Log log = LogFactory.getLog( IdentifierGeneratorFactory.class ); + + private static final HashMap GENERATORS = new HashMap(); + static { + GENERATORS.put( "uuid", UUIDHexGenerator.class ); + GENERATORS.put( "hilo", TableHiLoGenerator.class ); + GENERATORS.put( "assigned", Assigned.class ); + GENERATORS.put( "identity", IdentityGenerator.class ); + GENERATORS.put( "select", SelectGenerator.class ); + GENERATORS.put( "sequence", SequenceGenerator.class ); + GENERATORS.put( "seqhilo", SequenceHiLoGenerator.class ); + GENERATORS.put( "increment", IncrementGenerator.class ); + GENERATORS.put( "foreign", ForeignGenerator.class ); + GENERATORS.put( "guid", GUIDGenerator.class ); + GENERATORS.put( "uuid.hex", UUIDHexGenerator.class ); // uuid.hex is deprecated + GENERATORS.put( "sequence-identity", SequenceIdentityGenerator.class ); + } + + public static final Serializable SHORT_CIRCUIT_INDICATOR = new Serializable() { + public String toString() { + return "SHORT_CIRCUIT_INDICATOR"; + } + }; + + public static final Serializable POST_INSERT_INDICATOR = new Serializable() { + public String toString() { + return "POST_INSERT_INDICATOR"; + } + }; /** * Get the generated identifier when using identity columns + * + * @param rs The result set from which to extract the the generated identity. + * @param type The expected type mapping for the identity value. + * @return The generated identity value + * @throws SQLException Can be thrown while accessing the result set + * @throws HibernateException Indicates a problem reading back a generated identity value. */ - public static Serializable getGeneratedIdentity(ResultSet rs, Type type) - throws SQLException, HibernateException, IdentifierGenerationException { + public static Serializable getGeneratedIdentity(ResultSet rs, Type type) throws SQLException, HibernateException { if ( !rs.next() ) { throw new HibernateException( "The database returned no natively generated identity value" ); } final Serializable id = IdentifierGeneratorFactory.get( rs, type ); - if ( log.isDebugEnabled() ) log.debug( "Natively generated identity: " + id ); + if ( log.isDebugEnabled() ) { + log.debug( "Natively generated identity: " + id ); + } return id; } // unhappy about this being public ... is there a better way? - public static Serializable get(ResultSet rs, Type type) - throws SQLException, IdentifierGenerationException { - + public static Serializable get(ResultSet rs, Type type) throws SQLException, IdentifierGenerationException { Class clazz = type.getReturnedClass(); - if ( clazz==Long.class ) { - return new Long( rs.getLong(1) ); + if ( clazz == Long.class ) { + return new Long( rs.getLong( 1 ) ); } - else if ( clazz==Integer.class ) { - return new Integer( rs.getInt(1) ); + else if ( clazz == Integer.class ) { + return new Integer( rs.getInt( 1 ) ); } - else if ( clazz==Short.class ) { - return new Short( rs.getShort(1) ); + else if ( clazz == Short.class ) { + return new Short( rs.getShort( 1 ) ); } - else if ( clazz==String.class ) { - return rs.getString(1); + else if ( clazz == String.class ) { + return rs.getString( 1 ); } else { - throw new IdentifierGenerationException("this id generator generates long, integer, short or string"); + throw new IdentifierGenerationException( "this id generator generates long, integer, short or string" ); } - + } - private static final HashMap GENERATORS = new HashMap(); - - public static final Serializable SHORT_CIRCUIT_INDICATOR = new Serializable() { - public String toString() { return "SHORT_CIRCUIT_INDICATOR"; } - }; - - public static final Serializable POST_INSERT_INDICATOR = new Serializable() { - public String toString() { return "POST_INSERT_INDICATOR"; } - }; - - static { - GENERATORS.put("uuid", UUIDHexGenerator.class); - GENERATORS.put("hilo", TableHiLoGenerator.class); - GENERATORS.put("assigned", Assigned.class); - GENERATORS.put("identity", IdentityGenerator.class); - GENERATORS.put("select", SelectGenerator.class); - GENERATORS.put("sequence", SequenceGenerator.class); - GENERATORS.put("seqhilo", SequenceHiLoGenerator.class); - GENERATORS.put("increment", IncrementGenerator.class); - GENERATORS.put("foreign", ForeignGenerator.class); - GENERATORS.put("guid", GUIDGenerator.class); - GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated - GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class); - } - - public static IdentifierGenerator create(String strategy, Type type, Properties params, Dialect dialect) - throws MappingException { + public static IdentifierGenerator create(String strategy, Type type, Properties params, Dialect dialect) + throws MappingException { try { Class clazz = getIdentifierGeneratorClass( strategy, dialect ); - IdentifierGenerator idgen = (IdentifierGenerator) clazz.newInstance(); - if (idgen instanceof Configurable) ( (Configurable) idgen).configure(type, params, dialect); + IdentifierGenerator idgen = ( IdentifierGenerator ) clazz.newInstance(); + if ( idgen instanceof Configurable ) { + ( ( Configurable ) idgen ).configure( type, params, dialect ); + } return idgen; } - catch (Exception e) { - throw new MappingException("could not instantiate id generator", e); + catch ( Exception e ) { + throw new MappingException( + "could not instantiate id generator [entity-name=" + params.get( + IdentifierGenerator.ENTITY_NAME + ) + "]", e + ); } } public static Class getIdentifierGeneratorClass(String strategy, Dialect dialect) { - Class clazz = (Class) GENERATORS.get(strategy); - if ( "native".equals(strategy) ) clazz = dialect.getNativeIdentifierGeneratorClass(); - try { - if (clazz==null) clazz = ReflectHelper.classForName(strategy); + Class clazz = ( Class ) GENERATORS.get( strategy ); + if ( "native".equals( strategy ) ) { + clazz = dialect.getNativeIdentifierGeneratorClass(); } - catch (ClassNotFoundException e) { - throw new MappingException("could not interpret id generator strategy: " + strategy); + try { + if ( clazz == null ) { + clazz = ReflectHelper.classForName( strategy ); + } + } + catch ( ClassNotFoundException e ) { + throw new MappingException( "could not interpret id generator strategy: " + strategy ); } return clazz; } public static Number createNumber(long value, Class clazz) throws IdentifierGenerationException { - if ( clazz==Long.class ) { - return new Long(value); + if ( clazz == Long.class ) { + return new Long( value ); } - else if ( clazz==Integer.class ) { - return new Integer( (int) value ); + else if ( clazz == Integer.class ) { + return new Integer( ( int ) value ); } - else if ( clazz==Short.class ) { - return new Short( (short) value ); + else if ( clazz == Short.class ) { + return new Short( ( short ) value ); } else { - throw new IdentifierGenerationException("this id generator generates long, integer, short"); + throw new IdentifierGenerationException( "this id generator generates long, integer, short" ); } } - private IdentifierGeneratorFactory() {} //cannot be instantiated + /** + * Disallow instantiation. + */ + private IdentifierGeneratorFactory() { + } } diff --git a/src/org/hibernate/impl/IteratorImpl.java b/src/org/hibernate/impl/IteratorImpl.java index ae4caa6d2d..10cec56d81 100644 --- a/src/org/hibernate/impl/IteratorImpl.java +++ b/src/org/hibernate/impl/IteratorImpl.java @@ -34,7 +34,6 @@ public final class IteratorImpl implements HibernateIterator { private boolean hasNext; private final String[][] names; private PreparedStatement ps; - private Object nextResult; private HolderInstantiator holderInstantiator; public IteratorImpl( @@ -62,7 +61,6 @@ public final class IteratorImpl implements HibernateIterator { if (ps!=null) { try { log.debug("closing iterator"); - nextResult = null; session.getBatcher().closeQueryStatement(ps, rs); ps = null; rs = null; @@ -88,33 +86,15 @@ public final class IteratorImpl implements HibernateIterator { } } - private void postNext() throws HibernateException, SQLException { + private void postNext() throws SQLException { + log.debug("attempting to retrieve next results"); this.hasNext = rs.next(); if (!hasNext) { log.debug("exhausted results"); close(); } else { - log.debug("retrieving next results"); - boolean isHolder = holderInstantiator.isRequired(); - - if ( single && !isHolder ) { - nextResult = types[0].nullSafeGet( rs, names[0], session, null ); - } - else { - Object[] nextResults = new Object[types.length]; - for (int i=0; i= Connection.TRANSACTION_SERIALIZABLE; + } + finally { + if ( conn != null ) { + try { + sfi().getConnectionProvider().closeConnection( conn ); + } + catch ( Throwable ignore ) { + // ignore... + } + } + } + } /** * Is connection at least read committed? diff --git a/test/org/hibernate/test/AllTests.java b/test/org/hibernate/test/AllTests.java index fd560afd84..ac4defacf3 100644 --- a/test/org/hibernate/test/AllTests.java +++ b/test/org/hibernate/test/AllTests.java @@ -21,6 +21,7 @@ import org.hibernate.test.bidi.AuctionTest2; import org.hibernate.test.bytecode.BytecodeSuite; import org.hibernate.test.cache.CacheSuite; import org.hibernate.test.cascade.RefreshTest; +import org.hibernate.test.cfg.ListenerTest; import org.hibernate.test.cid.CompositeIdTest; import org.hibernate.test.collection.CollectionSuite; import org.hibernate.test.component.ComponentSuite; @@ -259,6 +260,7 @@ public class AllTests { suite.addTest( WhereTest.suite() ); suite.addTest( IterateTest.suite() ); suite.addTest( RefreshTest.suite() ); + suite.addTest( ListenerTest.suite() ); suite.addTest( ExtraLazyTest.suite() ); suite.addTest( StatsTest.suite() ); suite.addTest( SessionStatsTest.suite() ); diff --git a/test/org/hibernate/test/cfg/ListenerTest.java b/test/org/hibernate/test/cfg/ListenerTest.java new file mode 100644 index 0000000000..b88d805161 --- /dev/null +++ b/test/org/hibernate/test/cfg/ListenerTest.java @@ -0,0 +1,313 @@ +package org.hibernate.test.cfg; + +import java.util.Set; + +import junit.framework.Test; + +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.cfg.Configuration; +import org.hibernate.event.DeleteEvent; +import org.hibernate.event.DeleteEventListener; +import org.hibernate.event.def.DefaultDeleteEventListener; +import org.hibernate.junit.UnitTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Gail Badner + */ +public class ListenerTest extends UnitTestCase { + + public static class InvalidListenerForTest { + } + + public static class DeleteListenerForTest implements DeleteEventListener { + public void onDelete(DeleteEvent event) throws HibernateException { + } + + public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException { + } + } + + public static class AnotherDeleteListenerForTest implements DeleteEventListener { + public void onDelete(DeleteEvent event) throws HibernateException { + } + + public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException { + } + } + + public ListenerTest(String string) { + super( string ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ListenerTest.class ); + } + + public void testSetListenerNullClass() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListener( "delete", null ); + assertEquals( 0, cfg.getEventListeners().getDeleteEventListeners().length ); + } + + public void testSetListenersNullClass() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListeners( "delete", null ); + assertEquals( 0, cfg.getEventListeners().getDeleteEventListeners().length ); + } + + public void testSetListenerEmptyClassNameArray() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "delete", new String[] { } ); + fail( "should have thrown java.lang.ArrayStoreException" ); + } + catch ( ArrayStoreException ex ) { + // expected + } + } + + public void testSetListenersEmptyClassNsmeArray() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListeners( "delete", new String[] { } ); + assertEquals( 0, cfg.getEventListeners().getDeleteEventListeners().length ); + } + + public void testSetListenerEmptyClassObjectArray() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "delete", new Object[] { } ); + fail( "should have thrown java.lang.ArrayStoreException" ); + } + catch ( ArrayStoreException ex ) { + // expected + } + } + + public void testSetListenersEmptyClassObjectArray() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListeners( "delete", new Object[] { } ); + fail( "should have thrown ClassCastException" ); + } + catch ( ClassCastException ex ) { + // expected + } + } + + public void testSetListenerEmptyClassArray() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "delete", new DefaultDeleteEventListener[] { } ); + fail( "should have thrown java.lang.ArrayStoreException" ); + } + catch ( ArrayStoreException ex ) { + // expected + } + } + + public void testSetListenersEmptyClassArray() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListeners( "delete", new DefaultDeleteEventListener[] { } ); + assertEquals( 0, cfg.getEventListeners().getDeleteEventListeners().length ); + } + + public void testSetListenerUnknownClassName() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "delete", "UnknownClassName" ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenersUnknownClassName() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListeners( "delete", new String[] { "UnknownClassName" } ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenerInvalidClassName() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "delete", InvalidListenerForTest.class.getName() ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenersInvalidClassName() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListeners( "delete", new String[] { InvalidListenerForTest.class.getName() } ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenerClassName() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListener( "delete", DeleteListenerForTest.class.getName() ); + assertEquals( 1, cfg.getEventListeners().getDeleteEventListeners().length ); + assertTrue( cfg.getEventListeners().getDeleteEventListeners()[0] instanceof DeleteListenerForTest ); + } + + public void testSetListenersClassName() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListeners( "delete", new String[] { DeleteListenerForTest.class.getName() } ); + assertEquals( 1, cfg.getEventListeners().getDeleteEventListeners().length ); + assertTrue( cfg.getEventListeners().getDeleteEventListeners()[0] instanceof DeleteListenerForTest ); + } + + public void testSetListenerClassNames() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( + "delete", new String[] { + DeleteListenerForTest.class.getName(), + AnotherDeleteListenerForTest.class.getName() + } + ); + fail( "should have thrown java.lang.ArrayStoreException" ); + } + catch ( ArrayStoreException ex ) { + // expected + } + } + + public void testSetListenersClassNames() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListeners( + "delete", new String[] { + DeleteListenerForTest.class.getName(), + AnotherDeleteListenerForTest.class.getName() + } + ); + assertEquals( 2, cfg.getEventListeners().getDeleteEventListeners().length ); + assertTrue( cfg.getEventListeners().getDeleteEventListeners()[0] instanceof DeleteListenerForTest ); + assertTrue( cfg.getEventListeners().getDeleteEventListeners()[1] instanceof AnotherDeleteListenerForTest ); + } + + public void testSetListenerClassInstance() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListener( "delete", new DeleteListenerForTest() ); + assertEquals( 1, cfg.getEventListeners().getDeleteEventListeners().length ); + } + + public void testSetListenersClassInstances() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + cfg.setListeners( + "delete", new DeleteEventListener[] { + new DeleteListenerForTest(), + new AnotherDeleteListenerForTest() + } + ); + assertEquals( 2, cfg.getEventListeners().getDeleteEventListeners().length ); + assertTrue( cfg.getEventListeners().getDeleteEventListeners()[0] instanceof DeleteListenerForTest ); + assertTrue( cfg.getEventListeners().getDeleteEventListeners()[1] instanceof AnotherDeleteListenerForTest ); + } + + public void testSetListenerInvalidClassInstance() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "delete", new InvalidListenerForTest() ); + fail( "should have thrown java.lang.ArrayStoreException" ); + } + catch ( ArrayStoreException ex ) { + // expected + } + } + + public void testSetListenersInvalidClassInstances() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListeners( "delete", new InvalidListenerForTest[] { new InvalidListenerForTest() } ); + fail( "should have thrown java.lang.ClassCastException" ); + } + catch ( ClassCastException ex ) { + // expected + } + } + + public void testSetListenerNullType() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( null, new DeleteListenerForTest() ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenersNullType() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListeners( null, new DeleteEventListener[] { new DeleteListenerForTest() } ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenerUnknownType() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListener( "unknown-type", new DeleteListenerForTest() ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } + + public void testSetListenersUnknownType() { + Configuration cfg = new Configuration(); + assertNotNull( cfg.getEventListeners().getDeleteEventListeners() ); + try { + cfg.setListeners( "unknown-type", new DeleteEventListener[] { new DeleteListenerForTest() } ); + fail( "should have thrown MappingException" ); + } + catch ( MappingException ex ) { + // expected + } + } +} diff --git a/test/org/hibernate/test/filter/Category.hbm.xml b/test/org/hibernate/test/filter/Category.hbm.xml index 422875babb..42b78bf479 100644 --- a/test/org/hibernate/test/filter/Category.hbm.xml +++ b/test/org/hibernate/test/filter/Category.hbm.xml @@ -6,21 +6,24 @@ - - - + + + - - - + + + - - - - + + + + - + + + 'abc' in ( select d.reg from department d where (d.dept_id=123) union select p.name from sales_person p ) + - + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/DynamicFilterTest.java b/test/org/hibernate/test/filter/DynamicFilterTest.java index f6fdeef154..cd27fca8f0 100644 --- a/test/org/hibernate/test/filter/DynamicFilterTest.java +++ b/test/org/hibernate/test/filter/DynamicFilterTest.java @@ -67,6 +67,13 @@ public class DynamicFilterTest extends FunctionalTestCase { return new FunctionalTestClassTestSuite( DynamicFilterTest.class ); } + public void testSqlSyntaxOfFiltersWithUnions() { + Session session = openSession(); + session.enableFilter( "unioned" ); + session.createQuery( "from Category" ).list(); + session.close(); + } + public void testSecondLevelCachedCollectionsFiltering() { TestData testData = new TestData(); testData.prepare(); diff --git a/test/org/hibernate/test/filter/defs.hbm.xml b/test/org/hibernate/test/filter/defs.hbm.xml index f9305a83d2..dca3bce0b5 100644 --- a/test/org/hibernate/test/filter/defs.hbm.xml +++ b/test/org/hibernate/test/filter/defs.hbm.xml @@ -27,4 +27,8 @@ + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java b/test/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java index 2cb1cd5d4f..b791e74385 100644 --- a/test/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java +++ b/test/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java @@ -41,6 +41,12 @@ public class JPAQLComplianceTest extends AbstractJPATest { s.close(); } + public void testIdentifierCasesensitivityAndDuplicateFromElements() throws Exception { + Session s = openSession(); + s.createQuery( "select e from MyEntity e where exists (select 1 from MyEntity e2 where e2.other.name = 'something' and e2.other.other = e)" ); + s.close(); + } + public void testGeneratedSubquery() { Session s = openSession(); s.createQuery( "select c FROM Item c WHERE c.parts IS EMPTY" ).list(); diff --git a/test/org/hibernate/test/legacy/MasterDetailTest.java b/test/org/hibernate/test/legacy/MasterDetailTest.java index a9e06128a2..e85352dfc5 100644 --- a/test/org/hibernate/test/legacy/MasterDetailTest.java +++ b/test/org/hibernate/test/legacy/MasterDetailTest.java @@ -3,6 +3,7 @@ package org.hibernate.test.legacy; import java.io.Serializable; import java.sql.Connection; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -835,6 +836,10 @@ public class MasterDetailTest extends LegacyTestCase { } public void testCachedCollectionRefresh() throws Exception { + if ( isSerializableIsolationEnforced() ) { + reportSkip( "SERIALIZABLE isolation", "cached collection refreshing" ); + return; + } Session s = openSession(); Category c = new Category(); List list = new ArrayList(); @@ -853,7 +858,9 @@ public class MasterDetailTest extends LegacyTestCase { s.close(); s = openSession(); - if ( (getDialect() instanceof MySQLDialect) ) s.connection().setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + if ( (getDialect() instanceof MySQLDialect) ) { + s.connection().setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + } c = (Category) s.load(Category.class, id); c.getSubcategories().size(); //force load diff --git a/test/org/hibernate/test/reattachment/ProxyReattachmentTest.java b/test/org/hibernate/test/reattachment/ProxyReattachmentTest.java index ba12c74f8e..15e7f79c7e 100644 --- a/test/org/hibernate/test/reattachment/ProxyReattachmentTest.java +++ b/test/org/hibernate/test/reattachment/ProxyReattachmentTest.java @@ -1,5 +1,9 @@ package org.hibernate.test.reattachment; +import java.util.Set; +import java.util.Iterator; +import java.util.HashSet; + import junit.framework.Test; import org.hibernate.junit.functional.FunctionalTestCase; @@ -73,4 +77,151 @@ public class ProxyReattachmentTest extends FunctionalTestCase { s.getTransaction().commit(); s.close(); } + + public void testIterateWithClearTopOfLoop() { + Session s = openSession(); + s.beginTransaction(); + Set parents = new HashSet(); + for (int i=0; i<5; i++) { + Parent p = new Parent( String.valueOf( i ) ); + Child child = new Child( "child" + i ); + child.setParent( p ); + p.getChildren().add( child ); + s.save( p ); + parents.add(p); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + int i = 0; + for ( Iterator it = s.createQuery( "from Parent" ).iterate(); it.hasNext(); ) { + i++; + if (i % 2 == 0) { + s.flush(); + s.clear(); + } + Parent p = (Parent) it.next(); + assertEquals( 1, p.getChildren().size() ); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + for (Iterator it=parents.iterator(); it.hasNext(); ) { + s.delete(it.next()); + } + s.getTransaction().commit(); + s.close(); + } + + public void testIterateWithClearBottomOfLoop() { + Session s = openSession(); + s.beginTransaction(); + Set parents = new HashSet(); + for (int i=0; i<5; i++) { + Parent p = new Parent( String.valueOf( i ) ); + Child child = new Child( "child" + i ); + child.setParent( p ); + p.getChildren().add( child ); + s.save( p ); + parents.add(p); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + int i = 0; + for (Iterator it = s.createQuery( "from Parent" ).iterate(); it.hasNext(); ) { + Parent p = (Parent) it.next(); + assertEquals( 1, p.getChildren().size() ); + i++; + if (i % 2 == 0) { + s.flush(); + s.clear(); + } + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + for (Iterator it=parents.iterator(); it.hasNext(); ) { + s.delete(it.next()); + } + s.getTransaction().commit(); + s.close(); + } + + public void testIterateWithEvictTopOfLoop() { + Session s = openSession(); + s.beginTransaction(); + Set parents = new HashSet(); + for (int i=0; i<5; i++) { + Parent p = new Parent( String.valueOf( i + 100 ) ); + Child child = new Child( "child" + i ); + child.setParent( p ); + p.getChildren().add( child ); + s.save( p ); + parents.add(p); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + Parent p = null; + for (Iterator it = s.createQuery( "from Parent" ).iterate(); it.hasNext(); ) { + if ( p != null) { s.evict(p); } + p = (Parent) it.next(); + assertEquals( 1, p.getChildren().size() ); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + for (Iterator it=parents.iterator(); it.hasNext(); ) { + s.delete(it.next()); + } + s.getTransaction().commit(); + s.close(); + } + + public void testIterateWithEvictBottomOfLoop() { + Session s = openSession(); + s.beginTransaction(); + Set parents = new HashSet(); + for (int i=0; i<5; i++) { + Parent p = new Parent( String.valueOf( i + 100 ) ); + Child child = new Child( "child" + i ); + child.setParent( p ); + p.getChildren().add( child ); + s.save( p ); + parents.add(p); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + for (Iterator it = s.createQuery( "from Parent" ).iterate(); it.hasNext(); ) { + Parent p = (Parent) it.next(); + assertEquals( 1, p.getChildren().size() ); + s.evict(p); + } + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + for (Iterator it=parents.iterator(); it.hasNext(); ) { + s.delete(it.next()); + } + s.getTransaction().commit(); + s.close(); + } }