HHH-16541 Fix Sybase test issues and HSQLDB hanging

This commit is contained in:
Christian Beikov 2023-05-17 11:40:07 +02:00
parent a8c87cd284
commit b45edfc02d
6 changed files with 121 additions and 9 deletions

View File

@ -124,7 +124,7 @@ public class SybaseASELegacySqlAstTranslator<T extends JdbcOperation> extends Ab
appendSql( UNION_ALL ); appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length(); searchIndex = unionIndex + UNION_ALL.length();
} }
append( tableExpression, searchIndex, tableExpression.length() - 2 ); append( tableExpression, searchIndex, tableExpression.length() - 1 );
renderLockHint( lockMode ); renderLockHint( lockMode );
appendSql( " )" ); appendSql( " )" );

View File

@ -12,6 +12,7 @@ import java.util.function.Consumer;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
@ -25,6 +26,7 @@ import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.NamedTableReference; import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.UnionTableReference;
import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause; import org.hibernate.sql.ast.tree.select.SelectClause;
@ -37,6 +39,8 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
*/ */
public class SybaseAnywhereSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> { public class SybaseAnywhereSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
private static final String UNION_ALL = " union all ";
public SybaseAnywhereSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { public SybaseAnywhereSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
super( sessionFactory, statement ); super( sessionFactory, statement );
} }
@ -95,16 +99,48 @@ public class SybaseAnywhereSqlAstTranslator<T extends JdbcOperation> extends Abs
@Override @Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) { protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
super.renderNamedTableReference( tableReference, lockMode );
if ( getDialect().getVersion().isBefore( 10 ) ) { if ( getDialect().getVersion().isBefore( 10 ) ) {
if ( LockMode.READ.lessThan( lockMode ) ) { final String tableExpression = tableReference.getTableExpression();
appendSql( " holdlock" ); if ( tableReference instanceof UnionTableReference && lockMode != LockMode.NONE && tableExpression.charAt( 0 ) == '(' ) {
// SQL Server requires to push down the lock hint to the actual table names
int searchIndex = 0;
int unionIndex;
while ( ( unionIndex = tableExpression.indexOf( UNION_ALL, searchIndex ) ) != -1 ) {
append( tableExpression, searchIndex, unionIndex );
renderLockHint( lockMode );
appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length();
}
append( tableExpression, searchIndex, tableExpression.length() - 1 );
renderLockHint( lockMode );
appendSql( " )" );
registerAffectedTable( tableReference );
final Clause currentClause = getClauseStack().getCurrent();
if ( rendersTableReferenceAlias( currentClause ) ) {
final String identificationVariable = tableReference.getIdentificationVariable();
if ( identificationVariable != null ) {
appendSql( ' ' );
appendSql( identificationVariable );
}
}
} }
else {
super.renderNamedTableReference( tableReference, lockMode );
renderLockHint( lockMode );
}
// Just always return true because SQL Server doesn't support the FOR UPDATE clause
return true; return true;
} }
return false; return false;
} }
private void renderLockHint(LockMode lockMode) {
if ( LockMode.READ.lessThan( lockMode ) ) {
appendSql( " holdlock" );
}
}
@Override @Override
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
if ( getDialect().getVersion().isBefore( 10 ) ) { if ( getDialect().getVersion().isBefore( 10 ) ) {

View File

@ -12,6 +12,7 @@ import java.util.function.Consumer;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
@ -25,6 +26,7 @@ import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.NamedTableReference; import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.UnionTableReference;
import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
@ -36,6 +38,8 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
*/ */
public class SybaseLegacySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> { public class SybaseLegacySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
private static final String UNION_ALL = " union all ";
public SybaseLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { public SybaseLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
super( sessionFactory, statement ); super( sessionFactory, statement );
} }
@ -99,11 +103,43 @@ public class SybaseLegacySqlAstTranslator<T extends JdbcOperation> extends Abstr
@Override @Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) { protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
super.renderNamedTableReference( tableReference, lockMode ); final String tableExpression = tableReference.getTableExpression();
if ( tableReference instanceof UnionTableReference && lockMode != LockMode.NONE && tableExpression.charAt( 0 ) == '(' ) {
// SQL Server requires to push down the lock hint to the actual table names
int searchIndex = 0;
int unionIndex;
while ( ( unionIndex = tableExpression.indexOf( UNION_ALL, searchIndex ) ) != -1 ) {
append( tableExpression, searchIndex, unionIndex );
renderLockHint( lockMode );
appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length();
}
append( tableExpression, searchIndex, tableExpression.length() - 1 );
renderLockHint( lockMode );
appendSql( " )" );
registerAffectedTable( tableReference );
final Clause currentClause = getClauseStack().getCurrent();
if ( rendersTableReferenceAlias( currentClause ) ) {
final String identificationVariable = tableReference.getIdentificationVariable();
if ( identificationVariable != null ) {
appendSql( ' ' );
appendSql( identificationVariable );
}
}
}
else {
super.renderNamedTableReference( tableReference, lockMode );
renderLockHint( lockMode );
}
// Just always return true because SQL Server doesn't support the FOR UPDATE clause
return true;
}
private void renderLockHint(LockMode lockMode) {
if ( LockMode.READ.lessThan( lockMode ) ) { if ( LockMode.READ.lessThan( lockMode ) ) {
appendSql( " holdlock" ); appendSql( " holdlock" );
} }
return true;
} }
@Override @Override

View File

@ -124,7 +124,7 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
appendSql( UNION_ALL ); appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length(); searchIndex = unionIndex + UNION_ALL.length();
} }
append( tableExpression, searchIndex, tableExpression.length() - 2 ); append( tableExpression, searchIndex, tableExpression.length() - 1 );
renderLockHint( lockMode ); renderLockHint( lockMode );
appendSql( " )" ); appendSql( " )" );

View File

@ -10,8 +10,10 @@ import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
@ -25,6 +27,7 @@ import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.NamedTableReference; import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.UnionTableReference;
import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
@ -36,6 +39,8 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
*/ */
public class SybaseSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> { public class SybaseSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
private static final String UNION_ALL = " union all ";
public SybaseSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { public SybaseSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
super( sessionFactory, statement ); super( sessionFactory, statement );
} }
@ -99,11 +104,43 @@ public class SybaseSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
@Override @Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) { protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
super.renderNamedTableReference( tableReference, lockMode ); final String tableExpression = tableReference.getTableExpression();
if ( tableReference instanceof UnionTableReference && lockMode != LockMode.NONE && tableExpression.charAt( 0 ) == '(' ) {
// SQL Server requires to push down the lock hint to the actual table names
int searchIndex = 0;
int unionIndex;
while ( ( unionIndex = tableExpression.indexOf( UNION_ALL, searchIndex ) ) != -1 ) {
append( tableExpression, searchIndex, unionIndex );
renderLockHint( lockMode );
appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length();
}
append( tableExpression, searchIndex, tableExpression.length() - 1 );
renderLockHint( lockMode );
appendSql( " )" );
registerAffectedTable( tableReference );
final Clause currentClause = getClauseStack().getCurrent();
if ( rendersTableReferenceAlias( currentClause ) ) {
final String identificationVariable = tableReference.getIdentificationVariable();
if ( identificationVariable != null ) {
appendSql( ' ' );
appendSql( identificationVariable );
}
}
}
else {
super.renderNamedTableReference( tableReference, lockMode );
renderLockHint( lockMode );
}
// Just always return true because SQL Server doesn't support the FOR UPDATE clause
return true;
}
private void renderLockHint(LockMode lockMode) {
if ( LockMode.READ.lessThan( lockMode ) ) { if ( LockMode.READ.lessThan( lockMode ) ) {
appendSql( " holdlock" ); appendSql( " holdlock" );
} }
return true;
} }
@Override @Override

View File

@ -9,12 +9,14 @@ package org.hibernate.orm.test.locking.jpa;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.SkipForDialect;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -32,6 +34,7 @@ import static org.hibernate.jpa.SpecHints.HINT_SPEC_QUERY_TIMEOUT;
*/ */
@DomainModel(annotatedClasses = { Employee.class, Department.class }) @DomainModel(annotatedClasses = { Employee.class, Department.class })
@SessionFactory(useCollectingStatementInspector = true) @SessionFactory(useCollectingStatementInspector = true)
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "Seems HSQLDB doesn't cancel the query if it waits for a lock?!")
public class FollowOnLockingTest { public class FollowOnLockingTest {
@Test @Test