Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
this.maxLobPrefetchSize = configuration.getMaxLobPrefetchSize();
this.useUnicodeStringTypes = useUnicodeStringTypesDefault();

this.lockingSupport = buildLockingSupport();
this.lockingSupport = HANALockingSupport.forDialectVersion( configuration.getFullVersion() );
}

private LockingSupport buildLockingSupport() {
Expand Down Expand Up @@ -998,34 +998,18 @@
}

@Override
public String getReadLockString(String aliases, Timeout timeout) {
return getWriteLockString( aliases, timeout );
public String getForUpdateString(Timeout timeout) {
return withTimeout( getForUpdateString(), timeout.milliseconds() );
}

@Override
public String getWriteLockString(Timeout timeout) {
if ( Timeouts.isRealTimeout( timeout ) ) {
return getForUpdateString() + " wait " + getTimeoutInSeconds( timeout.milliseconds() );
}
else if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) {
return getForUpdateNowaitString();
}
else {
return getForUpdateString();
}
public String getReadLockString(String aliases, Timeout timeout) {
return getWriteLockString( aliases, timeout );
}

@Override
public String getWriteLockString(String aliases, Timeout timeout) {
if ( Timeouts.isRealTimeout( timeout ) ) {
return getForUpdateString( aliases ) + " wait " + getTimeoutInSeconds( timeout.milliseconds() );
}
else if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) {
return getForUpdateNowaitString( aliases );
}
else {
return getForUpdateString( aliases );
}
return withTimeout( getForUpdateString( aliases ), timeout.milliseconds() );
}

@Override
Expand All @@ -1039,29 +1023,17 @@
}

@Override
public String getWriteLockString(int timeout) {
if ( Timeouts.isRealTimeout( timeout ) ) {
return getForUpdateString() + " wait " + Timeouts.getTimeoutInSeconds( timeout );
}
else if ( timeout == Timeouts.NO_WAIT_MILLI ) {
return getForUpdateNowaitString();
}
else {
return getForUpdateString();
}
public String getWriteLockString(String aliases, int timeout) {
return withTimeout( getForUpdateString( aliases ), timeout );
}

@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout > 0 ) {
return getForUpdateString( aliases ) + " wait " + getTimeoutInSeconds( timeout );
}
else if ( timeout == 0 ) {
return getForUpdateNowaitString( aliases );
}
else {
return getForUpdateString( aliases );
}
private String withTimeout(String lockString, int timeout) {
return switch (timeout) {
case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString;

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.supportsNoWait
should be avoided because it has been deprecated.
case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + SQL_IGNORE_LOCKED : lockString;

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.supportsSkipLocked
should be avoided because it has been deprecated.
case Timeouts.WAIT_FOREVER_MILLI -> lockString;
default -> supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString;

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.supportsWait
should be avoided because it has been deprecated.

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.getTimeoutInSeconds
should be avoided because it has been deprecated.
};
}

@Override
Expand Down Expand Up @@ -2006,11 +1978,6 @@
getForUpdateString(aliases) + SQL_IGNORE_LOCKED : getForUpdateString(aliases);
}

@Override
public String getForUpdateString(LockMode lockMode) {
return super.getForUpdateString(lockMode);
}

@Override
public String getDual() {
return "sys.dummy";
Expand Down
56 changes: 14 additions & 42 deletions hibernate-core/src/main/java/org/hibernate/dialect/HANADialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -1003,34 +1003,18 @@
}

@Override
public String getReadLockString(String aliases, Timeout timeout) {
return getWriteLockString( aliases, timeout );
public String getForUpdateString(Timeout timeout) {
return withTimeout( getForUpdateString(), timeout.milliseconds() );
}

@Override
public String getWriteLockString(Timeout timeout) {
if ( Timeouts.isRealTimeout( timeout ) ) {
return getForUpdateString() + " wait " + Timeouts.getTimeoutInSeconds( timeout.milliseconds() );
}
else if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) {
return getForUpdateNowaitString();
}
else {
return getForUpdateString();
}
public String getReadLockString(String aliases, Timeout timeout) {
return getWriteLockString( aliases, timeout );
}

@Override
public String getWriteLockString(String aliases, Timeout timeout) {
if ( Timeouts.isRealTimeout( timeout ) ) {
return getForUpdateString( aliases ) + " wait " + getTimeoutInSeconds( timeout.milliseconds() );
}
else if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) {
return getForUpdateNowaitString( aliases );
}
else {
return getForUpdateString( aliases );
}
return withTimeout( getForUpdateString( aliases ), timeout.milliseconds() );
}

@Override
Expand All @@ -1044,29 +1028,17 @@
}

@Override
public String getWriteLockString(int timeout) {
if ( timeout > 0 ) {
return getForUpdateString() + " wait " + getTimeoutInSeconds( timeout );
}
else if ( timeout == Timeouts.NO_WAIT_MILLI ) {
return getForUpdateNowaitString();
}
else {
return getForUpdateString();
}
public String getWriteLockString(String aliases, int timeout) {
return withTimeout( getForUpdateString( aliases ), timeout );
}

@Override
public String getWriteLockString(String aliases, int timeout) {
if ( timeout > 0 ) {
return getForUpdateString( aliases ) + " wait " + getTimeoutInSeconds( timeout );
}
else if ( timeout == 0 ) {
return getForUpdateNowaitString( aliases );
}
else {
return getForUpdateString( aliases );
}
private String withTimeout(String lockString, int timeout) {
return switch (timeout) {
case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString;

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.supportsNoWait
should be avoided because it has been deprecated.
case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + SQL_IGNORE_LOCKED : lockString;

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.supportsSkipLocked
should be avoided because it has been deprecated.
case Timeouts.WAIT_FOREVER_MILLI -> lockString;
default -> supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString;

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.supportsWait
should be avoided because it has been deprecated.

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Dialect.getTimeoutInSeconds
should be avoided because it has been deprecated.
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
*/
package org.hibernate.dialect.lock.internal;

import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.dialect.lock.PessimisticLockStyle;
import org.hibernate.dialect.lock.spi.ConnectionLockTimeoutStrategy;
import org.hibernate.dialect.lock.spi.LockingSupport;
import org.hibernate.dialect.lock.spi.OuterJoinLockingType;

/**
Expand All @@ -15,14 +17,24 @@
* @author Steve Ebersole
*/
public class HANALockingSupport extends LockingSupportParameterized {
public static final HANALockingSupport HANA_LOCKING_SUPPORT = new HANALockingSupport( true );
public static final HANALockingSupport HANA_LOCKING_SUPPORT = new HANALockingSupport( true, true );

public static LockingSupport forDialectVersion(DatabaseVersion version) {
final boolean supportsWait = version.isSameOrAfter( 2, 0, 10 );
final boolean supportsSkipLocked = version.isSameOrAfter(2, 0, 30);
return new HANALockingSupport( supportsWait, supportsSkipLocked );
}

public HANALockingSupport(boolean supportsSkipLocked) {
this( false, supportsSkipLocked );
}

private HANALockingSupport(boolean supportsWait, boolean supportsSkipLocked) {
super(
PessimisticLockStyle.CLAUSE,
RowLockStrategy.COLUMN,
false,
false,
supportsWait,
supportsWait,
supportsSkipLocked,
OuterJoinLockingType.IDENTIFIED
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,26 @@
import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.TableDetails;
import org.hibernate.metamodel.mapping.ValuedModelPart;
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.mutation.EntityTableMapping;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.LockingClauseStrategy;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.model.TableMapping;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
Expand Down Expand Up @@ -212,21 +217,61 @@ private void addTableAliases(TableGroup tableGroup, List<String> lockItems) {
}

private void addColumnRefs(TableGroup tableGroup, List<String> lockItems) {
Collections.addAll( lockItems, determineKeyColumnRefs( tableGroup ) );
}

private String[] determineKeyColumnRefs(TableGroup tableGroup) {
final String[] keyColumns = determineKeyColumnNames( tableGroup.getModelPart() );
final String[] result = new String[keyColumns.length];
final String tableAlias = tableGroup.getPrimaryTableReference().getIdentificationVariable();
for ( int i = 0; i < keyColumns.length; i++ ) {
// NOTE: in some tests with Oracle, the qualifiers are being applied twice;
// still need to track that down. possibly, unexpected calls to
// `Dialect#applyLocksToSql`?
assert !keyColumns[i].contains( "." );
result[i] = tableAlias + "." + keyColumns[i];
lockItems.add( tableAlias + "." + keyColumns[i] );
}

final List<TableReferenceJoin> tableReferenceJoins = tableGroup.getTableReferenceJoins();
if ( CollectionHelper.isNotEmpty( tableReferenceJoins ) ) {
final EntityPersister entityPersister = determineEntityPersister( tableGroup.getModelPart() );
for ( int i = 0; i < tableReferenceJoins.size(); i++ ) {
final TableReferenceJoin tableReferenceJoin = tableReferenceJoins.get( i );
final NamedTableReference joinedTableReference = tableReferenceJoin.getJoinedTableReference();
final String tableJoinAlias = joinedTableReference.getIdentificationVariable();
final TableMapping tableMapping = determineTableMapping( entityPersister, tableReferenceJoin );
for ( TableDetails.KeyColumn keyColumn : tableMapping.getKeyDetails().getKeyColumns() ) {
lockItems.add( tableJoinAlias + "." + keyColumn.getColumnName() );
}
}
}
}

private TableMapping determineTableMapping(EntityPersister entityPersister, TableReferenceJoin tableReferenceJoin) {
final NamedTableReference joinedTableReference = tableReferenceJoin.getJoinedTableReference();
for ( EntityTableMapping tableMapping : entityPersister.getTableMappings() ) {
if ( joinedTableReference.containsAffectedTableName( tableMapping.getTableName() ) ) {
return tableMapping;
}
}
for ( EntityMappingType subMappingType : entityPersister.getSubMappingTypes() ) {
for ( EntityTableMapping tableMapping : subMappingType.getEntityPersister().getTableMappings() ) {
if ( joinedTableReference.containsAffectedTableName( tableMapping.getTableName() ) ) {
return tableMapping;
}
}
}
throw new IllegalArgumentException( "Couldn't find subclass index for joined table reference " + joinedTableReference );
}

private EntityPersister determineEntityPersister(ModelPartContainer modelPart) {
if ( modelPart instanceof EntityPersister entityPersister ) {
return entityPersister;
}
else if ( modelPart instanceof PluralAttributeMapping pluralAttributeMapping ) {
return pluralAttributeMapping.getCollectionDescriptor().getElementPersister();
}
else if ( modelPart instanceof EntityAssociationMapping entityAssociationMapping ) {
return entityAssociationMapping.getAssociatedEntityMappingType().getEntityPersister();
}
else {
throw new IllegalArgumentException( "Expected table group with table joins to have an entity typed model part but got: " + modelPart );
}
return result;
}

private String[] determineKeyColumnNames(ModelPart modelPart) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ public void testLockTimeoutNoAliasNoWait() {
@Test
public void testLockTimeoutNoAliasSkipLocked() {
assertEquals(
" for update",
" for update ignore locked",
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ ).setTimeout( SKIP_LOCKED ) )
);
assertEquals(
" for update",
" for update ignore locked",
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE ).setTimeout( SKIP_LOCKED ) )
);
}
Expand Down Expand Up @@ -100,15 +100,15 @@ public void testLockTimeoutAliasNoWait() {
public void testLockTimeoutAliasSkipLocked() {
String alias = "a";
assertEquals(
" for update of a",
" for update of a ignore locked",
dialect.getForUpdateString(
alias,
new LockOptions( LockMode.PESSIMISTIC_READ )
.setTimeout( SKIP_LOCKED )
)
);
assertEquals(
" for update of a",
" for update of a ignore locked",
dialect.getForUpdateString(
alias,
new LockOptions( LockMode.PESSIMISTIC_WRITE )
Expand Down