HHH-11640 - NamedQuery doesn't log comment when UPDATE/DELETE
HHH-11906 - Add support for MySQL query optimizer hints
This commit is contained in:
parent
08cd580067
commit
72506a6eac
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
|
||||
if ( StringHelper.isEmpty( hint ) ) {
|
||||
return sql;
|
||||
}
|
||||
public String getQueryHintString(String sql, String hints) {
|
||||
String statementType = statementType(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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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( ";" );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in New Issue