HHH-10654 - Fix mariadb and pgsql failing tests
This commit is contained in:
parent
19c03e0c5a
commit
5fd186a010
|
@ -23,6 +23,7 @@ import javax.persistence.PessimisticLockException;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
import javax.persistence.QueryTimeoutException;
|
import javax.persistence.QueryTimeoutException;
|
||||||
|
|
||||||
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
|
@ -40,6 +41,8 @@ import org.hibernate.testing.RequiresDialect;
|
||||||
import org.hibernate.testing.RequiresDialectFeature;
|
import org.hibernate.testing.RequiresDialectFeature;
|
||||||
import org.hibernate.testing.SkipForDialect;
|
import org.hibernate.testing.SkipForDialect;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.transaction.TransactionUtil;
|
||||||
|
import org.hibernate.testing.util.ExceptionUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -156,19 +159,23 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Map<String, Object> properties = new HashMap<>();
|
Map<String, Object> properties = new HashMap<>();
|
||||||
properties.put( org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT, -2L );
|
properties.put( org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT, LockOptions.SKIP_LOCKED );
|
||||||
em2.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_READ, properties );
|
em2.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_READ, properties );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
TransactionUtil.setJdbcTimeout( entityManager.unwrap( Session.class ) );
|
||||||
entityManager.createNativeQuery( updateStatement() )
|
entityManager.createNativeQuery( updateStatement() )
|
||||||
.setParameter( "name", "changed" )
|
.setParameter( "name", "changed" )
|
||||||
.setParameter( "id", lock.getId() )
|
.setParameter( "id", lock.getId() )
|
||||||
.executeUpdate();
|
.executeUpdate();
|
||||||
} );
|
} );
|
||||||
fail("Should throw LockTimeoutException");
|
fail("Should throw Exception");
|
||||||
}
|
}
|
||||||
catch (LockTimeoutException expected) {
|
catch (Exception e) {
|
||||||
|
if ( !ExceptionUtil.isSqlLockTimeout( e) ) {
|
||||||
|
fail( "Unknown exception thrown: " + e.getMessage() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -202,13 +209,16 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
try {
|
try {
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
try {
|
try {
|
||||||
|
TransactionUtil.setJdbcTimeout( entityManager.unwrap( Session.class ) );
|
||||||
entityManager.createNativeQuery( updateStatement() )
|
entityManager.createNativeQuery( updateStatement() )
|
||||||
.setParameter( "name", "changed" )
|
.setParameter( "name", "changed" )
|
||||||
.setParameter( "id", lock.getId() )
|
.setParameter( "id", lock.getId() )
|
||||||
.executeUpdate();
|
.executeUpdate();
|
||||||
}
|
}
|
||||||
catch (LockTimeoutException | PessimisticLockException expected) {
|
catch (Exception e) {
|
||||||
failureExpected.set( true );
|
if ( ExceptionUtil.isSqlLockTimeout( e ) ) {
|
||||||
|
failureExpected.set( true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.query.criteria.internal.expression;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
@ -16,6 +18,11 @@ import javax.persistence.criteria.Expression;
|
||||||
import javax.persistence.criteria.Path;
|
import javax.persistence.criteria.Path;
|
||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||||
|
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.SkipForDialect;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -29,7 +36,8 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase {
|
public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseClause() {
|
@RequiresDialect(H2Dialect.class)
|
||||||
|
public void testCaseClause() {
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
CriteriaBuilder cb = session.getCriteriaBuilder();
|
CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
|
|
||||||
|
@ -87,6 +95,7 @@ public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
private EventType type;
|
private EventType type;
|
||||||
|
|
||||||
protected Event() {
|
protected Event() {
|
||||||
|
|
|
@ -7,19 +7,17 @@
|
||||||
package org.hibernate.test.locking;
|
package org.hibernate.test.locking;
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.PessimisticLockException;
|
|
||||||
import org.hibernate.dialect.SQLServerDialect;
|
import org.hibernate.dialect.SQLServerDialect;
|
||||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||||
import org.hibernate.exception.GenericJDBCException;
|
|
||||||
import org.hibernate.exception.LockAcquisitionException;
|
|
||||||
|
|
||||||
import org.hibernate.testing.SkipForDialect;
|
import org.hibernate.testing.SkipForDialect;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.transaction.TransactionUtil;
|
||||||
|
import org.hibernate.testing.util.ExceptionUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
@ -164,43 +162,38 @@ public class LockModeTest extends BaseCoreFunctionalTestCase {
|
||||||
// until the txn in the calling method completed.
|
// until the txn in the calling method completed.
|
||||||
// To be able to cater to the second type, we run this block in a separate thread to be able to "time it out"
|
// To be able to cater to the second type, we run this block in a separate thread to be able to "time it out"
|
||||||
|
|
||||||
executeSync( () -> {
|
try {
|
||||||
doInHibernate( this::sessionFactory, _session -> {
|
executeSync( () -> {
|
||||||
_session.doWork( connection -> {
|
doInHibernate( this::sessionFactory, _session -> {
|
||||||
|
TransactionUtil.setJdbcTimeout( _session );
|
||||||
try {
|
try {
|
||||||
connection.setNetworkTimeout( Executors.newSingleThreadExecutor(), 1000);
|
// load with write lock to deal with databases that block (wait indefinitely) direct attempts
|
||||||
} catch (Throwable ignore) {
|
// to write a locked row
|
||||||
ignore.fillInStackTrace();
|
A it = _session.get(
|
||||||
|
A.class,
|
||||||
|
id,
|
||||||
|
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setTimeOut( LockOptions.NO_WAIT )
|
||||||
|
);
|
||||||
|
_session.createNativeQuery( updateStatement() )
|
||||||
|
.setParameter( "value", "changed" )
|
||||||
|
.setParameter( "id", it.getId() )
|
||||||
|
.executeUpdate();
|
||||||
|
fail( "Pessimistic lock not obtained/held" );
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
if ( !ExceptionUtil.isSqlLockTimeout( e) ) {
|
||||||
|
fail( "Unexpected error type testing pessimistic locking : " + e.getClass().getName() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
try {
|
|
||||||
// load with write lock to deal with databases that block (wait indefinitely) direct attempts
|
|
||||||
// to write a locked row
|
|
||||||
A it = _session.get(
|
|
||||||
A.class,
|
|
||||||
id,
|
|
||||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setTimeOut( LockOptions.NO_WAIT )
|
|
||||||
);
|
|
||||||
_session.createNativeQuery( updateStatement() )
|
|
||||||
.setParameter( "value", "changed" )
|
|
||||||
.setParameter( "id", it.getId() )
|
|
||||||
.executeUpdate();
|
|
||||||
fail( "Pessimistic lock not obtained/held" );
|
|
||||||
}
|
|
||||||
catch ( Exception e ) {
|
|
||||||
// grr, exception can be any number of types based on database
|
|
||||||
// see HHH-6887
|
|
||||||
if ( LockAcquisitionException.class.isInstance( e )
|
|
||||||
|| GenericJDBCException.class.isInstance( e )
|
|
||||||
|| PessimisticLockException.class.isInstance( e ) ) {
|
|
||||||
// "ok"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fail( "Unexpected error type testing pessimistic locking : " + e.getClass().getName() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
} );
|
||||||
} );
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
//MariaDB throws a time out nd closes the underlying connection
|
||||||
|
if( !ExceptionUtil.isConnectionClose(e)) {
|
||||||
|
fail("Unknown exception thrown: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String updateStatement() {
|
protected String updateStatement() {
|
||||||
|
|
|
@ -91,7 +91,7 @@ public abstract class BaseUnitTestCase {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
catch (ExecutionException e) {
|
catch (ExecutionException e) {
|
||||||
throw new RuntimeException( e );
|
throw new RuntimeException( e.getCause() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.testing.transaction;
|
package org.hibernate.testing.transaction;
|
||||||
|
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -13,16 +15,25 @@ import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.persistence.EntityTransaction;
|
import javax.persistence.EntityTransaction;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionBuilder;
|
import org.hibernate.SessionBuilder;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
import org.hibernate.dialect.MySQLDialect;
|
||||||
|
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vlad Mihalcea
|
* @author Vlad Mihalcea
|
||||||
*/
|
*/
|
||||||
public class TransactionUtil {
|
public class TransactionUtil {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger( TransactionUtil.class );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hibernate transaction function
|
* Hibernate transaction function
|
||||||
*
|
*
|
||||||
|
@ -322,4 +333,38 @@ public class TransactionUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Session or Statement timeout
|
||||||
|
* @param session Hibernate Session
|
||||||
|
*/
|
||||||
|
public static void setJdbcTimeout(Session session) {
|
||||||
|
session.doWork( connection -> {
|
||||||
|
if ( Dialect.getDialect() instanceof PostgreSQL81Dialect ) {
|
||||||
|
try (Statement st = connection.createStatement()) {
|
||||||
|
st.execute( "SET statement_timeout TO 1000" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if( Dialect.getDialect() instanceof MySQLDialect ) {
|
||||||
|
try (Statement st = connection.createStatement()) {
|
||||||
|
st.execute( "SET GLOBAL innodb_lock_wait_timeout = 1" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( Dialect.getDialect() instanceof H2Dialect ) {
|
||||||
|
try (Statement st = connection.createStatement()) {
|
||||||
|
st.execute( "SET LOCK_TIMEOUT 100" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
connection.setNetworkTimeout( Executors.newSingleThreadExecutor(), 1000 );
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) {
|
||||||
|
ignore.fillInStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package org.hibernate.testing.util;
|
||||||
|
|
||||||
|
import javax.persistence.LockTimeoutException;
|
||||||
|
|
||||||
|
import org.hibernate.PessimisticLockException;
|
||||||
|
import org.hibernate.exception.GenericJDBCException;
|
||||||
|
import org.hibernate.exception.JDBCConnectionException;
|
||||||
|
import org.hibernate.exception.LockAcquisitionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class ExceptionUtil {
|
||||||
|
|
||||||
|
private static final ExceptionUtil INSTANCE = new ExceptionUtil();
|
||||||
|
|
||||||
|
public static ExceptionUtil getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExceptionUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root cause of a particular {@code Throwable}
|
||||||
|
*
|
||||||
|
* @param t exception
|
||||||
|
*
|
||||||
|
* @return exception root cause
|
||||||
|
*/
|
||||||
|
public static Throwable rootCause(Throwable t) {
|
||||||
|
Throwable cause = t.getCause();
|
||||||
|
if ( cause != null && cause != t ) {
|
||||||
|
return rootCause( cause );
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was the given exception caused by a SQL lock timeout?
|
||||||
|
*
|
||||||
|
* @param e exception
|
||||||
|
*
|
||||||
|
* @return is caused by a SQL lock timeout
|
||||||
|
*/
|
||||||
|
public static boolean isSqlLockTimeout(Exception e) {
|
||||||
|
// grr, exception can be any number of types based on database
|
||||||
|
// see HHH-6887
|
||||||
|
if ( LockAcquisitionException.class.isInstance( e )
|
||||||
|
|| LockTimeoutException.class.isInstance( e )
|
||||||
|
|| GenericJDBCException.class.isInstance( e )
|
||||||
|
|| PessimisticLockException.class.isInstance( e )
|
||||||
|
|| javax.persistence.PessimisticLockException.class.isInstance( e )
|
||||||
|
|| JDBCConnectionException.class.isInstance( e ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Throwable rootCause = ExceptionUtil.rootCause( e );
|
||||||
|
if ( rootCause != null && (
|
||||||
|
rootCause.getMessage().contains( "timeout" ) ||
|
||||||
|
rootCause.getMessage().contains( "timed out" ) )
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was the given exception caused by a SQL connection close
|
||||||
|
*
|
||||||
|
* @param e exception
|
||||||
|
*
|
||||||
|
* @return is caused by a SQL connection close
|
||||||
|
*/
|
||||||
|
public static boolean isConnectionClose(Exception e) {
|
||||||
|
Throwable rootCause = ExceptionUtil.rootCause( e );
|
||||||
|
if ( rootCause != null && (
|
||||||
|
rootCause.getMessage().toLowerCase().contains( "connection is close" )
|
||||||
|
) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue