HHH-13239 - The query hint javax.persistence.lock.timeout doesn't work correctly on HANA

Convert the lock wait timeout to seconds by dividing the timeout by 1000 (i.e. ignoring the fractions of a second)
This commit is contained in:
Jonathan Bregler 2019-01-30 15:07:54 +01:00 committed by Vlad Mihalcea
parent a36df5f259
commit 0750716c87
2 changed files with 70 additions and 4 deletions

View File

@ -29,6 +29,7 @@ import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
import java.sql.Types;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
@ -1452,10 +1453,11 @@ public abstract class AbstractHANADialect extends Dialect {
@Override
public String getWriteLockString(int timeout) {
if ( timeout > 0 ) {
return getForUpdateString() + " wait " + timeout;
long timeoutInSeconds = getLockWaitTimeoutInSeconds( timeout );
if ( timeoutInSeconds > 0 ) {
return getForUpdateString() + " wait " + timeoutInSeconds;
}
else if ( timeout == 0 ) {
else if ( timeoutInSeconds == 0 ) {
return getForUpdateNowaitString();
}
else {
@ -1466,7 +1468,7 @@ public abstract class AbstractHANADialect extends Dialect {
@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout > 0 ) {
return getForUpdateString( aliases ) + " wait " + timeout;
return getForUpdateString( aliases ) + " wait " + getLockWaitTimeoutInSeconds( timeout );
}
else if ( timeout == 0 ) {
return getForUpdateNowaitString( aliases );
@ -1476,6 +1478,16 @@ public abstract class AbstractHANADialect extends Dialect {
}
}
private long getLockWaitTimeoutInSeconds(int timeoutInMilliseconds) {
Duration duration = Duration.ofMillis( timeoutInMilliseconds );
long timeoutInSeconds = duration.getSeconds();
if ( duration.getNano() != 0 ) {
LOG.info( "Changing the query timeout from " + timeoutInMilliseconds + " ms to " + timeoutInSeconds
+ " s, because HANA requires the timeout in seconds" );
}
return timeoutInSeconds;
}
@Override
public String getQueryHintString(String query, List<String> hints) {
return query + " with hint (" + String.join( ",", hints ) + ")";

View File

@ -0,0 +1,54 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
public class HANADialectTestCase extends BaseUnitTestCase {
@Test
@TestForIssue(jiraKey = "HHH-13239")
public void testLockWaitTimeout() {
HANAColumnStoreDialect dialect = new HANAColumnStoreDialect();
String sql = "select dummy from sys.dummy";
LockOptions lockOptions = new LockOptions( LockMode.PESSIMISTIC_WRITE );
lockOptions.setTimeOut( 2000 );
Map<String, String[]> keyColumns = new HashMap<>();
String sqlWithLock = dialect.applyLocksToSql( sql, lockOptions, new HashMap<>() );
assertEquals( sql + " for update wait 2", sqlWithLock );
lockOptions.setTimeOut( 0 );
sqlWithLock = dialect.applyLocksToSql( sql, lockOptions, new HashMap<>() );
assertEquals( sql + " for update nowait", sqlWithLock );
lockOptions.setTimeOut( 500 );
sqlWithLock = dialect.applyLocksToSql( sql, lockOptions, new HashMap<>() );
assertEquals( sql + " for update nowait", sqlWithLock );
lockOptions.setTimeOut( 1500 );
sqlWithLock = dialect.applyLocksToSql( sql, lockOptions, new HashMap<>() );
assertEquals( sql + " for update wait 1", sqlWithLock );
lockOptions.setAliasSpecificLockMode( "dummy", LockMode.PESSIMISTIC_READ );
keyColumns.put( "dummy", new String[]{ "dummy" } );
sqlWithLock = dialect.applyLocksToSql( sql, lockOptions, keyColumns );
assertEquals( sql + " for update of dummy.dummy wait 1", sqlWithLock );
}
}