diff --git a/hibernate-core/src/main/java/org/hibernate/criterion/DetachedCriteria.java b/hibernate-core/src/main/java/org/hibernate/criterion/DetachedCriteria.java index 2bf0f8bc42..1f166ae0d5 100755 --- a/hibernate-core/src/main/java/org/hibernate/criterion/DetachedCriteria.java +++ b/hibernate-core/src/main/java/org/hibernate/criterion/DetachedCriteria.java @@ -420,6 +420,19 @@ public class DetachedCriteria implements CriteriaSpecification, Serializable { criteria.setLockMode( alias, lockMode ); return this; } + + /** + * Set a timeout for the underlying JDBC query. + * + * @param timeout The timeout value to apply. + * @return this (for method chaining) + * + * @see java.sql.Statement#setQueryTimeout + */ + public DetachedCriteria setTimeout(int timeout) { + criteria.setTimeout( timeout ); + return this; + } @Override public String toString() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java index 7d13f076c9..30a68f7465 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java @@ -6,6 +6,8 @@ */ package org.hibernate.test.criteria; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -23,6 +25,7 @@ import org.hibernate.QueryException; import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.Transaction; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.criterion.DetachedCriteria; @@ -48,23 +51,31 @@ import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.test.hql.Animal; import org.hibernate.test.hql.Reptile; +import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider; import org.junit.Test; +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; /** * @author Gavin King * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) */ @RequiresDialectFeature(DialectChecks.SupportsSequences.class) -public class CriteriaQueryTest extends BaseCoreFunctionalTestCase { +public class CriteriaQueryTest extends BaseNonConfigCoreFunctionalTestCase { + + private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider(); + @Override public String[] getMappings() { return new String[] { @@ -73,12 +84,24 @@ public class CriteriaQueryTest extends BaseCoreFunctionalTestCase { } @Override - public void configure(Configuration cfg) { - super.configure( cfg ); - cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); - cfg.setProperty( Environment.CACHE_REGION_PREFIX, "criteriaquerytest" ); - cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); - cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + protected void addSettings(Map settings) { + settings.put( AvailableSettings.USE_QUERY_CACHE, "true" ); + settings.put( + AvailableSettings.CACHE_REGION_PREFIX, + "criteriaquerytest" + ); + settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" ); + settings.put( AvailableSettings.GENERATE_STATISTICS, "true" ); + settings.put( + AvailableSettings.CONNECTION_PROVIDER, + connectionProvider + ); + } + + @Override + protected void releaseResources() { + super.releaseResources(); + connectionProvider.stop(); } @Test @@ -432,6 +455,35 @@ public class CriteriaQueryTest extends BaseCoreFunctionalTestCase { session.close(); } + @Test + public void testDetachedCriteriaTimeout() { + doInHibernate( this::sessionFactory, session -> { + DetachedCriteria dc = DetachedCriteria.forClass(Student.class) + .setTimeout( 100 ); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(232); + + session.persist(gavin); + session.flush(); + + connectionProvider.clear(); + List result = dc.getExecutableCriteria(session).list(); + PreparedStatement preparedStatement = connectionProvider.getPreparedStatements().get( 0 ); + try { + verify(preparedStatement, times(1)).setQueryTimeout( 100 ); + } + catch (SQLException e) { + fail(e.getMessage()); + } + + assertEquals( result.size(), 1 ); + + session.delete(gavin); + } ); + } + @Test public void testProjectionCache() { Session s = openSession();