HHH-11640 - NamedQuery doesn't log comment when UPDATE/DELETE

HHH-11906 - Add support for MySQL query optimizer hints
This commit is contained in:
Ivo Hradek 2017-07-31 15:19:44 +02:00 committed by Vlad Mihalcea
parent 08cd580067
commit 72506a6eac
16 changed files with 539 additions and 69 deletions

View File

@ -2788,6 +2788,24 @@ public abstract class Dialect implements ConversionContext {
return true;
}
/**
* Apply a hint to the query. The entire query is provided, allowing the Dialect full control over the placement
* and syntax of the hint. By default, ignore the hint and simply return the query.
*
* @param query The query to which to apply the hint.
* @param hintList The hints to apply
* @return The modified SQL
*/
public String getQueryHintString(String query, List<String> hintList) {
final String hints = StringHelper.join( ", ", hintList.iterator() );
if ( StringHelper.isEmpty( hints ) ) {
return query;
}
return getQueryHintString( query, hints );
}
/**
* Apply a hint to the query. The entire query is provided, allowing the Dialect full control over the placement
* and syntax of the hint. By default, ignore the hint and simply return the query.
@ -2796,7 +2814,7 @@ public abstract class Dialect implements ConversionContext {
* @param hints The hints to apply
* @return The modified SQL
*/
public String getQueryHintString(String query, List<String> hints) {
public String getQueryHintString(String query, String hints) {
return query;
}
@ -2949,4 +2967,32 @@ public abstract class Dialect implements ConversionContext {
false
);
}
/**
* Modify the SQL, adding hints or comments, if necessary
*
* @param sql original sql
* @param parameters query parameters
* @param commentsEnabled if comments are enabled
*/
public String addSqlHintOrComment(
String sql,
QueryParameters parameters,
boolean commentsEnabled) {
// Keep this here, rather than moving to Select. Some Dialects may need the hint to be appended to the very
// end or beginning of the finalized SQL statement, so wait until everything is processed.
if ( parameters.getQueryHints() != null && parameters.getQueryHints().size() > 0 ) {
sql = getQueryHintString( sql, parameters.getQueryHints() );
}
else if ( commentsEnabled && parameters.getComment() != null ){
sql = prependComment( sql, parameters.getComment() );
}
return sql;
}
protected String prependComment(String sql, String comment) {
return "/* " + comment + " */ " + sql;
}
}

View File

@ -17,6 +17,7 @@ import org.hibernate.dialect.function.AvgWithArgumentCastFunction;
import org.hibernate.dialect.function.NoArgSQLFunction;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
@ -441,4 +442,9 @@ public class H2Dialect extends Dialect {
public IdentityColumnSupport getIdentityColumnSupport() {
return new H2IdentityColumnSupport();
}
@Override
public String getQueryHintString(String query, String hints) {
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
}
}

View File

@ -9,6 +9,7 @@ package org.hibernate.dialect;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
@ -54,4 +55,9 @@ public class MySQL5Dialect extends MySQLDialect {
}
};
@Override
public String getQueryHintString(String query, String hints) {
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
}
}

View File

@ -12,6 +12,7 @@ import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.JDBCException;
@ -65,6 +66,8 @@ public class Oracle8iDialect extends Dialect {
private static final Pattern UNION_KEYWORD_PATTERN = Pattern.compile( "\\bunion\\b" );
private static final Pattern SQL_STATEMENT_TYPE_PATTERN = Pattern.compile("^\\s*(select|insert|update|delete)\\s+.*?");
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
@ -669,21 +672,21 @@ public class Oracle8iDialect extends Dialect {
}
@Override
public String getQueryHintString(String sql, List<String> hints) {
final String hint = StringHelper.join( ", ", hints.iterator() );
public String getQueryHintString(String sql, String hints) {
String statementType = statementType(sql);
if ( StringHelper.isEmpty( hint ) ) {
return sql;
}
final int pos = sql.indexOf( "select" );
final int pos = sql.indexOf( statementType );
if ( pos > -1 ) {
final StringBuilder buffer = new StringBuilder( sql.length() + hint.length() + 8 );
final StringBuilder buffer = new StringBuilder( sql.length() + hints.length() + 8 );
if ( pos > 0 ) {
buffer.append( sql.substring( 0, pos ) );
}
buffer.append( "select /*+ " ).append( hint ).append( " */" )
.append( sql.substring( pos + "select".length() ) );
buffer
.append( statementType )
.append( " /*+ " )
.append( hints )
.append( " */" )
.append( sql.substring( pos + statementType.length() ) );
sql = buffer.toString();
}
@ -711,4 +714,14 @@ public class Oracle8iDialect extends Dialect {
public boolean supportsPartitionBy() {
return true;
}
protected String statementType(String sql) {
Matcher matcher = SQL_STATEMENT_TYPE_PATTERN.matcher( sql );
if(matcher.matches() && matcher.groupCount() == 1) {
return matcher.group(1);
}
throw new IllegalArgumentException( "Can't determine SQL statement type for statement: " + sql );
}
}

View File

@ -55,16 +55,10 @@ public class SQLServer2012Dialect extends SQLServer2008Dialect {
}
@Override
public String getQueryHintString(String sql, List<String> hints) {
final String hint = StringHelper.join( ", ", hints.iterator() );
if ( StringHelper.isEmpty( hint ) ) {
return sql;
}
public String getQueryHintString(String sql, String hints) {
final StringBuilder buffer = new StringBuilder(
sql.length()
+ hint.length() + 12
+ hints.length() + 12
);
final int pos = sql.indexOf( ";" );
if ( pos > -1 ) {
@ -73,7 +67,7 @@ public class SQLServer2012Dialect extends SQLServer2008Dialect {
else {
buffer.append( sql );
}
buffer.append( " OPTION (" ).append( hint ).append( ")" );
buffer.append( " OPTION (" ).append( hints ).append( ")" );
if ( pos > -1 ) {
buffer.append( ";" );
}

View File

@ -0,0 +1,48 @@
/*
* 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.hint;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Adds an INDEX query hint as follows:
*
* <code>
* SELECT *
* FROM TEST
* USE INDEX (hint1, hint2)
* WHERE X=1
* </code>
*
* @author Vlad Mihalcea
*/
public class IndexQueryHintHandler implements QueryHintHandler {
public static final IndexQueryHintHandler INSTANCE = new IndexQueryHintHandler();
private static final Pattern QUERY_PATTERN = Pattern.compile( "^(select.*?from.*?)(where.*?)$" );
@Override
public String addQueryHints(String query, String hints) {
Matcher matcher = QUERY_PATTERN.matcher( query );
if ( matcher.matches() && matcher.groupCount() > 1 ) {
String startToken = matcher.group( 1 );
String endToken = matcher.group( 2 );
return new StringBuilder( startToken )
.append( " USE INDEX (" )
.append( hints )
.append( ") " )
.append( endToken )
.toString();
}
else {
return query;
}
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.hint;
/**
* Contract defining how query hints get applied.
*
* @author Vlad Mihalcea
*/
public interface QueryHintHandler {
/**
* Add query hints to the given query.
*
* @param query original query
* @param hints hints to be applied
* @return query with hints
*/
String addQueryHints(String query, String hints);
}

View File

@ -183,7 +183,12 @@ public class NativeSQLQueryPlan implements Serializable {
PreparedStatement ps;
try {
queryParameters.processFilters( this.customQuery.getSQL(), session );
final String sql = queryParameters.getFilteredSQL();
final String sql = session.getJdbcServices().getDialect()
.addSqlHintOrComment(
queryParameters.getFilteredSQL(),
queryParameters,
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
);
ps = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );

View File

@ -56,7 +56,17 @@ public class BasicExecutor implements StatementExecutor {
@Override
public int execute(QueryParameters parameters, SharedSessionContractImplementor session) throws HibernateException {
return doExecute( parameters, session, sql, parameterSpecifications );
return doExecute(
parameters,
session,
session.getJdbcServices().getDialect()
.addSqlHintOrComment(
sql,
parameters,
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
),
parameterSpecifications
);
}
protected int doExecute(QueryParameters parameters, SharedSessionContractImplementor session, String sql,

View File

@ -29,6 +29,7 @@ import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.WrongClassException;
import org.hibernate.cache.spi.FilterKey;
@ -235,21 +236,20 @@ public abstract class Loader {
protected String preprocessSQL(
String sql,
QueryParameters parameters,
Dialect dialect,
SessionFactoryImplementor sessionFactory,
List<AfterLoadAction> afterLoadActions) throws HibernateException {
Dialect dialect = sessionFactory.getServiceRegistry().getService( JdbcServices.class ).getDialect();
sql = applyLocks( sql, parameters, dialect, afterLoadActions );
// Keep this here, rather than moving to Select. Some Dialects may need the hint to be appended to the very
// end or beginning of the finalized SQL statement, so wait until everything is processed.
if ( parameters.getQueryHints() != null && parameters.getQueryHints().size() > 0 ) {
sql = dialect.getQueryHintString( sql, parameters.getQueryHints() );
}
sql = dialect.addSqlHintOrComment(
sql,
parameters,
sessionFactory.getSessionFactoryOptions().isCommentsEnabled()
);
sql = processDistinctKeyword( sql, parameters);
return getFactory().getSessionFactoryOptions().isCommentsEnabled()
? prependComment( sql, parameters )
: sql;
return processDistinctKeyword( sql, parameters );
}
protected boolean shouldUseFollowOnLocking(
@ -299,16 +299,6 @@ public abstract class Loader {
return lockModeToUse;
}
private String prependComment(String sql, QueryParameters parameters) {
String comment = parameters.getComment();
if ( comment == null ) {
return sql;
}
else {
return "/* " + comment + " */ " + sql;
}
}
/**
* Execute an SQL query and attempt to instantiate instances of the class mapped by the given
* persister from each row of the <tt>ResultSet</tt>. If an object is supplied, will attempt to
@ -1920,7 +1910,7 @@ public abstract class Loader {
String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() );
// Adding locks and comments.
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect(), afterLoadActions );
sql = preprocessSQL( sql, queryParameters, getFactory(), afterLoadActions );
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );

View File

@ -180,7 +180,12 @@ public abstract class AbstractLoadPlanBasedLoader {
String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() );
// Adding locks and comments.
sql = preprocessSQL( sql, queryParameters, session.getJdbcServices().getJdbcEnvironment().getDialect(), afterLoadActions );
sql = session.getJdbcServices().getJdbcEnvironment().getDialect()
.addSqlHintOrComment(
sql,
queryParameters,
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
);
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
return new SqlStatementWrapper( st, getResultSet( st, queryParameters.getRowSelection(), limitHandler, queryParameters.hasAutoDiscoverScalarTypes(), session ) );
@ -198,26 +203,6 @@ public abstract class AbstractLoadPlanBasedLoader {
return LimitHelper.useLimit( limitHandler, selection ) ? limitHandler : NoopLimitHandler.INSTANCE;
}
private String preprocessSQL(
String sql,
QueryParameters queryParameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) {
return getFactory().getSettings().isCommentsEnabled()
? prependComment( sql, queryParameters )
: sql;
}
private String prependComment(String sql, QueryParameters parameters) {
final String comment = parameters.getComment();
if ( comment == null ) {
return sql;
}
else {
return "/* " + comment + " */ " + sql;
}
}
/**
* Obtain a <tt>PreparedStatement</tt> with all parameters pre-bound.
* Bind JDBC-style <tt>?</tt> parameters, named parameters, and

View File

@ -0,0 +1,336 @@
/*
* 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.jpa.test.query;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.TypedQuery;
import org.hibernate.Session;
import org.hibernate.annotations.NamedNativeQuery;
import org.hibernate.annotations.NamedQuery;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author Vlad Mihalcea
*/
@TestForIssue(jiraKey = "HHH-11640")
public class NamedQueryCommentTest extends BaseEntityManagerFunctionalTestCase {
private PreparedStatementSpyConnectionProvider connectionProvider;
@Override
protected Map getConfig() {
Map config = super.getConfig();
config.put(
org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER,
connectionProvider
);
config.put(
AvailableSettings.USE_SQL_COMMENTS,
Boolean.TRUE.toString()
);
return config;
}
@Override
public void buildEntityManagerFactory() throws Exception {
connectionProvider = new PreparedStatementSpyConnectionProvider();
super.buildEntityManagerFactory();
}
@Override
public void releaseResources() {
super.releaseResources();
connectionProvider.stop();
}
private static final String[] GAME_TITLES = { "Halo", "Grand Theft Auto", "NetHack" };
@Override
public Class[] getAnnotatedClasses() {
return new Class[] { Game.class };
}
@Override
protected void addConfigOptions(Map options) {
options.put( AvailableSettings.USE_SQL_COMMENTS, Boolean.TRUE.toString() );
}
@Before
public void setUp() {
doInJPA( this::entityManagerFactory, entityManager -> {
for ( String title : GAME_TITLES ) {
Game game = new Game( title );
entityManager.persist( game );
}
} );
}
@After
public void tearDown() {
doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.createQuery( "delete from Game" ).executeUpdate();
} );
}
@Test
public void testSelectNamedQueryWithSqlComment() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
TypedQuery<Game> query = entityManager.createNamedQuery( "SelectNamedQuery", Game.class );
query.setParameter( "title", GAME_TITLES[0] );
List<Game> list = query.getResultList();
assertEquals( 1, list.size() );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"/* INDEX (game idx_game_title) */ select namedquery0_.id as id1_0_, namedquery0_.title as title2_0_ from game namedquery0_ where namedquery0_.title=?"
)
);
} );
}
@Test
public void testSelectNamedNativeQueryWithSqlComment() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
TypedQuery<Game> query = entityManager.createNamedQuery( "SelectNamedNativeQuery", Game.class );
query.setParameter( "title", GAME_TITLES[0] );
List<Game> list = query.getResultList();
assertEquals( 1, list.size() );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"/* + INDEX (game idx_game_title) */ select * from Game g where title = ?"
)
);
} );
}
@Test
public void testUpdateNamedQueryWithSqlComment() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
Query query = entityManager.createNamedQuery( "UpdateNamedNativeQuery" );
query.setParameter( "title", GAME_TITLES[0] );
query.setParameter( "id", 1L );
int updateCount = query.executeUpdate();
assertEquals( 1, updateCount );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"/* INDEX (game idx_game_title) */ update game set title = ? where id = ?"
)
);
} );
}
@Test
public void testUpdateNamedNativeQueryWithSqlComment() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
Query query = entityManager.createNamedQuery( "UpdateNamedNativeQuery" );
query.setParameter( "title", GAME_TITLES[0] );
query.setParameter( "id", 1L );
int updateCount = query.executeUpdate();
assertEquals( 1, updateCount );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"/* INDEX (game idx_game_title) */ update game set title = ? where id = ?"
)
);
} );
}
@Test
@RequiresDialect(Oracle8iDialect.class)
public void testUpdateNamedNativeQueryWithQueryHintUsingOracle() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
Query query = entityManager.createNamedQuery( "UpdateNamedNativeQuery" );
query.setParameter( "title", GAME_TITLES[0] );
query.setParameter( "id", 1L );
query.unwrap( org.hibernate.query.Query.class ).addQueryHint( "INDEX (game idx_game_id)" );
int updateCount = query.executeUpdate();
assertEquals( 1, updateCount );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"update /*+ INDEX (game idx_game_id) */ game set title = ? where id = ?"
)
);
} );
}
@Test
@RequiresDialect(H2Dialect.class)
public void testUpdateNamedNativeQueryWithQueryHintUsingIndex() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
Query query = entityManager.createNamedQuery( "UpdateNamedNativeQuery" );
query.setParameter( "title", GAME_TITLES[0] );
query.setParameter( "id", 1L );
query.unwrap( org.hibernate.query.Query.class ).addQueryHint( "INDEX (game idx_game_id)" );
int updateCount = query.executeUpdate();
assertEquals( 1, updateCount );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"update game set title = ? where id = ?"
)
);
} );
}
@Test
@RequiresDialect(MySQLDialect.class)
@RequiresDialect(H2Dialect.class)
public void testSelectNamedNativeQueryWithQueryHintUsingIndex() {
doInJPA( this::entityManagerFactory, entityManager -> {
connectionProvider.clear();
Query query = entityManager.createNamedQuery( "SelectNamedQuery" );
query.setParameter( "title", GAME_TITLES[0] );
query.unwrap( org.hibernate.query.Query.class ).addQueryHint( "idx_game_id" );
List<Game> list = query.getResultList();
assertEquals( 1, list.size() );
assertEquals(
1,
connectionProvider.getPreparedStatements().size()
);
assertNotNull(
connectionProvider.getPreparedStatement(
"select namedquery0_.id as id1_0_, namedquery0_.title as title2_0_ from game namedquery0_ USE INDEX (idx_game_id) where namedquery0_.title=?"
)
);
} );
}
@Entity(name = "Game")
@Table(
name = "game",
indexes = {
@Index(name = "idx_game_title", columnList = "title"),
@Index(name = "idx_game_id", columnList = "id")
}
)
@NamedQuery(
name = "SelectNamedQuery",
query = "select g from Game g where title = :title",
comment = "INDEX (game idx_game_title)"
)
@NamedQuery(
name = "UpdateNamedQuery",
query = "update Game set title = :title where id = :id",
comment = "INDEX (game idx_game_title) "
)
@NamedNativeQuery(
name = "SelectNamedNativeQuery",
query = "select * from Game g where title = :title",
comment = "+ INDEX (game idx_game_title) ",
resultClass = Game.class
)
@NamedNativeQuery(
name = "UpdateNamedNativeQuery",
query = "update game set title = :title where id = :id",
comment = "INDEX (game idx_game_title) ",
resultClass = Game.class
)
public static class Game {
@Id
@GeneratedValue
private Long id;
private String title;
public Game() {
}
public Game(String title) {
this.title = title;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
}

View File

@ -1375,6 +1375,7 @@ public class FooBarTest extends LegacyTestCase {
}
@Test
@SkipForDialect( value = H2Dialect.class, comment = "Feature not supported: MVCC=TRUE && FOR UPDATE && JOIN")
public void testQueryLockMode() throws Exception {
Session s = openSession();
Transaction tx = s.beginTransaction();
@ -4029,6 +4030,7 @@ public class FooBarTest extends LegacyTestCase {
}
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA currently requires specifying table name by 'FOR UPDATE of t1.c1' if there are more than one tables/views/subqueries in the FROM clause")
@SkipForDialect( value = H2Dialect.class, comment = "Feature not supported: MVCC=TRUE && FOR UPDATE && JOIN")
@Test
public void testNewSessionLifecycle() throws Exception {
Session s = openSession();
@ -4309,6 +4311,7 @@ public class FooBarTest extends LegacyTestCase {
}
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA currently requires specifying table name by 'FOR UPDATE of t1.c1' if there are more than one tables/views/subqueries in the FROM clause")
@SkipForDialect( value = H2Dialect.class, comment = "Feature not supported: MVCC=TRUE && FOR UPDATE && JOIN")
@Test
public void testRefresh() throws Exception {
final Session s = openSession();

View File

@ -30,6 +30,7 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jdbc.Work;
@ -369,7 +370,8 @@ public class MultiTableTest extends LegacyTestCase {
// HANA currently requires specifying table name by 'FOR UPDATE of t1.c1'
// if there are more than one tables/views/subqueries in the FROM clause
if ( !( getDialect() instanceof AbstractHANADialect ) ) {
// H2 - Feature not supported: MVCC=TRUE && FOR UPDATE && JOIN
if ( !( getDialect() instanceof AbstractHANADialect || getDialect() instanceof H2Dialect ) ) {
s = openSession();
t = s.beginTransaction();
multi = (Multi) s.load( Top.class, mid, LockMode.UPGRADE );
@ -491,7 +493,8 @@ public class MultiTableTest extends LegacyTestCase {
// HANA currently requires specifying table name by 'FOR UPDATE of t1.c1'
// if there are more than one tables/views/subqueries in the FROM clause
if ( !( getDialect() instanceof AbstractHANADialect ) ) {
// H2 - Feature not supported: MVCC=TRUE && FOR UPDATE && JOIN
if ( !( getDialect() instanceof AbstractHANADialect || getDialect() instanceof H2Dialect ) ) {
s = openSession();
t = s.beginTransaction();
multi = (Multi) s.load( Top.class, multiId, LockMode.UPGRADE );

View File

@ -32,6 +32,7 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.IngresDialect;
import org.hibernate.dialect.MySQLDialect;
@ -225,6 +226,7 @@ public class ParentChildTest extends LegacyTestCase {
}
@Test
@SkipForDialect( value = H2Dialect.class, comment = "Feature not supported: MVCC=TRUE && FOR UPDATE && JOIN")
public void testComplexCriteria() throws Exception {
Session s = openSession();
Transaction t = s.beginTransaction();

View File

@ -10,8 +10,7 @@
ext {
junitVersion = '4.12'
// h2Version = '1.2.145'
h2Version = '1.3.176'
h2Version = '1.4.196'
bytemanVersion = '4.0.0-BETA5'
infinispanVersion = '8.2.5.Final'
jnpVersion = '5.0.6.CR1'