Re-enabled additional tests
This commit is contained in:
parent
e7992a35d4
commit
0e1822e5dd
|
@ -93,7 +93,7 @@ public class OracleDialect extends Dialect {
|
|||
private static final Pattern GROUP_BY_KEYWORD_PATTERN = Pattern.compile( "\\bgroup\\sby\\b" );
|
||||
private static final Pattern ORDER_BY_KEYWORD_PATTERN = Pattern.compile( "\\border\\sby\\b" );
|
||||
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 Pattern SQL_STATEMENT_TYPE_PATTERN = Pattern.compile("^(?:/\\*.*?\\*/)?\\s*(select|insert|update|delete)\\s+.*?", Pattern.CASE_INSENSITIVE);
|
||||
private static final int PARAM_LIST_SIZE_LIMIT = 1000;
|
||||
|
||||
public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw";
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* 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.orm.test.queryhint;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
@RequiresDialect(value = OracleDialect.class, version = 800)
|
||||
@DomainModel(
|
||||
annotatedClasses = { OracleQueryHintTest.Employee.class, OracleQueryHintTest.Department.class }
|
||||
)
|
||||
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
|
||||
@ServiceRegistry(
|
||||
settings = @Setting(name = AvailableSettings.USE_SQL_COMMENTS, value = "true")
|
||||
)
|
||||
public class OracleQueryHintTest {
|
||||
|
||||
@BeforeAll
|
||||
protected void setUp(SessionFactoryScope scope) {
|
||||
Department department = new Department();
|
||||
department.name = "Sales";
|
||||
Employee employee1 = new Employee();
|
||||
employee1.department = department;
|
||||
Employee employee2 = new Employee();
|
||||
employee2.department = department;
|
||||
|
||||
scope.inTransaction( s -> {
|
||||
s.persist( department );
|
||||
s.persist( employee1 );
|
||||
s.persist( employee2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryHint(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
// test Query w/ a simple Oracle optimizer hint
|
||||
scope.inTransaction( s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals( 2, results.size() );
|
||||
} );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
assertTrue( statementInspector.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS */" ) );
|
||||
statementInspector.clear();
|
||||
|
||||
// test multiple hints
|
||||
scope.inTransaction( s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.addQueryHint( "USE_CONCAT" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
} );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
assertTrue( statementInspector.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS, USE_CONCAT */" ) );
|
||||
statementInspector.clear();
|
||||
|
||||
// ensure the insertion logic can handle a comment appended to the front
|
||||
scope.inTransaction( s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.setComment( "this is a test" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
} );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( statementInspector.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS */" ) );
|
||||
statementInspector.clear();
|
||||
|
||||
// test Criteria
|
||||
scope.inTransaction( s -> {
|
||||
final CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Employee> criteria = criteriaBuilder.createQuery( Employee.class );
|
||||
Root<Employee> root = criteria.from( Employee.class );
|
||||
Join<Object, Object> departmentJoin = root.join( "department" );
|
||||
criteria.select( root ).where( criteriaBuilder.equal( departmentJoin.get( "name" ), "Sales" ) );
|
||||
// Criteria criteria = s.createCriteria( Employee.class )
|
||||
// .addQueryHint( "ALL_ROWS" )
|
||||
// .createCriteria( "department" ).add( Restrictions.eq( "name", "Sales" ) );
|
||||
Query<Employee> query = s.createQuery( criteria );
|
||||
query.addQueryHint( "ALL_ROWS" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
} );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( statementInspector.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS */" ) );
|
||||
statementInspector.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12362")
|
||||
public void testQueryHintAndComment(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setComment( "My_Query" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
} );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( statementInspector.getSqlQueries()
|
||||
.get( 0 )
|
||||
.contains( "/* My_Query */ select /*+ ALL_ROWS */" ) );
|
||||
statementInspector.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-13608")
|
||||
public void testQueryHintCaseInsensitive(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( s -> {
|
||||
List results = s.createNativeQuery(
|
||||
"SELECT e.id as id " +
|
||||
"FROM Employee e " +
|
||||
"JOIN Department d ON e.department_id = d.id " +
|
||||
"WHERE d.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setComment( "My_Query" )
|
||||
.setParameter( "departmentName", "Sales" )
|
||||
.getResultList();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
} );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( statementInspector.getSqlQueries()
|
||||
.get( 0 )
|
||||
.contains( "/* My_Query */ SELECT /*+ ALL_ROWS */" ) );
|
||||
statementInspector.clear();
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
public Department department;
|
||||
}
|
||||
|
||||
@Entity(name = "Department")
|
||||
public static class Department {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
public String name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
|
||||
/*
|
||||
* 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.orm.test.queryhint;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.SQLServer2012Dialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
|
||||
@RequiresDialect(value = SQLServerDialect.class, version = 11)
|
||||
@DomainModel(
|
||||
annotatedClasses = { QueryHintSQLServer2012Test.Employee.class, QueryHintSQLServer2012Test.Department.class }
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = @Setting(name = AvailableSettings.USE_SQL_COMMENTS, value = "true"),
|
||||
settingProviders = @SettingProvider(provider = QueryHintSQLServer2012Test.DialectProvider.class, settingName = AvailableSettings.DIALECT)
|
||||
)
|
||||
public class QueryHintSQLServer2012Test {
|
||||
|
||||
public static class DialectProvider implements SettingProvider.Provider<String> {
|
||||
|
||||
@Override
|
||||
public String getSetting() {
|
||||
return QueryHintTestSQLServer2012Dialect.class.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryHint(SessionFactoryScope scope) {
|
||||
Department department = new Department();
|
||||
department.name = "Sales";
|
||||
Employee employee1 = new Employee();
|
||||
employee1.department = department;
|
||||
Employee employee2 = new Employee();
|
||||
employee2.department = department;
|
||||
|
||||
List result = scope.fromSession(
|
||||
session -> {
|
||||
session.getTransaction().begin();
|
||||
session.persist( department );
|
||||
session.persist( employee1 );
|
||||
session.persist( employee2 );
|
||||
|
||||
try {
|
||||
session.getTransaction().commit();
|
||||
session.clear();
|
||||
|
||||
// test Query w/ a simple SQLServer2012 optimizer hint
|
||||
session.getTransaction().begin();
|
||||
Query query = session.createQuery(
|
||||
"FROM QueryHintSQLServer2012Test$Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint(
|
||||
"MAXDOP 2" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
session.getTransaction().commit();
|
||||
session.clear();
|
||||
|
||||
assertEquals( 2, results.size() );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql()
|
||||
.contains( "OPTION (MAXDOP 2)" ) );
|
||||
|
||||
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
|
||||
|
||||
// test multiple hints
|
||||
session.getTransaction().begin();
|
||||
query = session.createQuery(
|
||||
"FROM QueryHintSQLServer2012Test$Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "MAXDOP 2" )
|
||||
.addQueryHint( "CONCAT UNION" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
results = query.list();
|
||||
session.getTransaction().commit();
|
||||
session.clear();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "MAXDOP 2" ) );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "CONCAT UNION" ) );
|
||||
|
||||
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
|
||||
|
||||
// ensure the insertion logic can handle a comment appended to the front
|
||||
session.getTransaction().begin();
|
||||
query = session.createQuery(
|
||||
"FROM QueryHintSQLServer2012Test$Employee e WHERE e.department.name = :departmentName" )
|
||||
.setComment( "this is a test" )
|
||||
.addQueryHint( "MAXDOP 2" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
results = query.list();
|
||||
session.getTransaction().commit();
|
||||
session.clear();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql()
|
||||
.contains( "OPTION (MAXDOP 2)" ) );
|
||||
|
||||
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
|
||||
|
||||
// test Criteria
|
||||
session.getTransaction().begin();
|
||||
|
||||
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<Employee> criteria = criteriaBuilder.createQuery( Employee.class );
|
||||
Root<Employee> root = criteria.from( Employee.class );
|
||||
Join<Object, Object> departement = root.join( "department", JoinType.INNER );
|
||||
criteria.select( root ).where( criteriaBuilder.equal( departement.get( "name" ), "Sales" ) );
|
||||
// Criteria criteria = s.createCriteria( Employee.class ).addQueryHint( "MAXDOP 2" ).createCriteria( "department" )
|
||||
// .add( Restrictions.eq( "name", "Sales" ) );
|
||||
// results = criteria.list();
|
||||
Query<Employee> criteriaQuery = session.createQuery( criteria );
|
||||
criteriaQuery.addQueryHint( "MAXDOP 2" );
|
||||
results = criteriaQuery.list();
|
||||
session.getTransaction().commit();
|
||||
return results;
|
||||
}
|
||||
finally {
|
||||
if ( session.getTransaction().isActive() ) {
|
||||
session.getTransaction().rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
assertEquals( result.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "OPTION (MAXDOP 2)" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the query hint is added to the SQL during Loader's executeQueryStatement -> preprocessSQL, rather than
|
||||
* early on during the QueryTranslator or QueryLoader initialization, there's not an easy way to check the full SQL
|
||||
* after completely processing it. Instead, use this ridiculous hack to ensure Loader actually calls Dialect. TODO:
|
||||
* This is terrible. Better ideas?
|
||||
*/
|
||||
public static class QueryHintTestSQLServer2012Dialect extends SQLServer2012Dialect {
|
||||
|
||||
private static String processedSql;
|
||||
|
||||
@Override
|
||||
public String getQueryHintString(String sql, List<String> hints) {
|
||||
processedSql = super.getQueryHintString( sql, hints );
|
||||
return processedSql;
|
||||
}
|
||||
|
||||
public static String getProcessedSql() {
|
||||
return processedSql;
|
||||
}
|
||||
|
||||
public static void resetProcessedSql() {
|
||||
processedSql = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Employee {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
@ManyToOne
|
||||
public Department department;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Department {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
public String name;
|
||||
}
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
* 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.test.queryhint;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Oracle8iDialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
@RequiresDialect( Oracle8iDialect.class )
|
||||
public class OracleQueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put( AvailableSettings.USE_SQL_COMMENTS, "true" );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( settings );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Employee.class, Department.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterSessionFactoryBuilt(SessionFactoryImplementor sessionFactory) {
|
||||
Department department = new Department();
|
||||
department.name = "Sales";
|
||||
Employee employee1 = new Employee();
|
||||
employee1.department = department;
|
||||
Employee employee2 = new Employee();
|
||||
employee2.department = department;
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.persist( department );
|
||||
s.persist( employee1 );
|
||||
s.persist( employee2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryHint() {
|
||||
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
// test Query w/ a simple Oracle optimizer hint
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
// test multiple hints
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.addQueryHint( "USE_CONCAT" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS, USE_CONCAT */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
// ensure the insertion logic can handle a comment appended to the front
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.setComment( "this is a test" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
// test Criteria
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
final CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Employee> criteria = criteriaBuilder.createQuery( Employee.class );
|
||||
Root<Employee> root = criteria.from( Employee.class );
|
||||
Join<Object, Object> departmentJoin = root.join( "department" );
|
||||
criteria.select( root ).where( criteriaBuilder.equal( departmentJoin.get( "name" ),"Sales" ) );
|
||||
// Criteria criteria = s.createCriteria( Employee.class )
|
||||
// .addQueryHint( "ALL_ROWS" )
|
||||
// .createCriteria( "department" ).add( Restrictions.eq( "name", "Sales" ) );
|
||||
Query<Employee> query = s.createQuery( criteria );
|
||||
query.addQueryHint( "ALL_ROWS" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "select /*+ ALL_ROWS */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-12362" )
|
||||
public void testQueryHintAndComment() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Query query = s.createQuery( "FROM Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setComment( "My_Query" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "/* My_Query */ select /*+ ALL_ROWS */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-13608")
|
||||
public void testQueryHintCaseInsensitive() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
List results = s.createNativeQuery(
|
||||
"SELECT e.id as id " +
|
||||
"FROM Employee e " +
|
||||
"JOIN Department d ON e.department_id = d.id " +
|
||||
"WHERE d.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setComment( "My_Query" )
|
||||
.setParameter( "departmentName", "Sales" )
|
||||
.getResultList();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "/* My_Query */ SELECT /*+ ALL_ROWS */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
public Department department;
|
||||
}
|
||||
|
||||
@Entity(name = "Department")
|
||||
public static class Department {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
public String name;
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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.test.queryhint;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.SQLServer2012Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
|
||||
@RequiresDialect(SQLServer2012Dialect.class)
|
||||
public class QueryHintSQLServer2012Test extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Employee.class, Department.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
configuration.setProperty( AvailableSettings.DIALECT, QueryHintTestSQLServer2012Dialect.class.getName() );
|
||||
configuration.setProperty( AvailableSettings.USE_SQL_COMMENTS, "true" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryHint() {
|
||||
Department department = new Department();
|
||||
department.name = "Sales";
|
||||
Employee employee1 = new Employee();
|
||||
employee1.department = department;
|
||||
Employee employee2 = new Employee();
|
||||
employee2.department = department;
|
||||
|
||||
Session s = openSession();
|
||||
s.getTransaction().begin();
|
||||
s.persist( department );
|
||||
s.persist( employee1 );
|
||||
s.persist( employee2 );
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
// test Query w/ a simple SQLServer2012 optimizer hint
|
||||
s.getTransaction().begin();
|
||||
Query query = s.createQuery( "FROM QueryHintSQLServer2012Test$Employee e WHERE e.department.name = :departmentName" ).addQueryHint( "MAXDOP 2" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
List results = query.list();
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "OPTION (MAXDOP 2)" ) );
|
||||
|
||||
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
|
||||
|
||||
// test multiple hints
|
||||
s.getTransaction().begin();
|
||||
query = s.createQuery( "FROM QueryHintSQLServer2012Test$Employee e WHERE e.department.name = :departmentName" )
|
||||
.addQueryHint("MAXDOP 2")
|
||||
.addQueryHint("CONCAT UNION")
|
||||
.setParameter("departmentName", "Sales");
|
||||
results = query.list();
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "MAXDOP 2" ) );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "CONCAT UNION" ) );
|
||||
|
||||
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
|
||||
|
||||
// ensure the insertion logic can handle a comment appended to the front
|
||||
s.getTransaction().begin();
|
||||
query = s.createQuery( "FROM QueryHintSQLServer2012Test$Employee e WHERE e.department.name = :departmentName" ).setComment( "this is a test" )
|
||||
.addQueryHint( "MAXDOP 2" )
|
||||
.setParameter( "departmentName", "Sales" );
|
||||
results = query.list();
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "OPTION (MAXDOP 2)" ) );
|
||||
|
||||
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
|
||||
|
||||
// test Criteria
|
||||
s.getTransaction().begin();
|
||||
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Employee> criteria = criteriaBuilder.createQuery( Employee.class );
|
||||
Root<Employee> root = criteria.from( Employee.class );
|
||||
Join<Object, Object> departement = root.join( "departement", JoinType.INNER );
|
||||
criteria.select( root ).where( criteriaBuilder.equal( departement.get( "name" ), "Sales" ) );
|
||||
// Criteria criteria = s.createCriteria( Employee.class ).addQueryHint( "MAXDOP 2" ).createCriteria( "department" )
|
||||
// .add( Restrictions.eq( "name", "Sales" ) );
|
||||
// results = criteria.list();
|
||||
Query<Employee> criteriaQuery = s.createQuery( criteria );
|
||||
criteriaQuery.addQueryHint( "MAXDOP 2" );
|
||||
results = criteriaQuery.list();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertEquals( results.size(), 2 );
|
||||
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "OPTION (MAXDOP 2)" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the query hint is added to the SQL during Loader's executeQueryStatement -> preprocessSQL, rather than
|
||||
* early on during the QueryTranslator or QueryLoader initialization, there's not an easy way to check the full SQL
|
||||
* after completely processing it. Instead, use this ridiculous hack to ensure Loader actually calls Dialect. TODO:
|
||||
* This is terrible. Better ideas?
|
||||
*/
|
||||
public static class QueryHintTestSQLServer2012Dialect extends SQLServer2012Dialect {
|
||||
|
||||
private static String processedSql;
|
||||
|
||||
@Override
|
||||
public String getQueryHintString(String sql, List<String> hints) {
|
||||
processedSql = super.getQueryHintString( sql, hints );
|
||||
return processedSql;
|
||||
}
|
||||
|
||||
public static String getProcessedSql() {
|
||||
return processedSql;
|
||||
}
|
||||
|
||||
public static void resetProcessedSql() {
|
||||
processedSql = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Employee {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
@ManyToOne
|
||||
public Department department;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Department {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public long id;
|
||||
|
||||
public String name;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue