enable query hints for SQL Server 2012

This commit is contained in:
magdalena 2015-01-03 13:38:29 +01:00
parent 1b9cd19ca7
commit bbaeaa6c58
2 changed files with 205 additions and 0 deletions

View File

@ -23,7 +23,10 @@
*/
package org.hibernate.dialect;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.internal.util.StringHelper;
/**
* Microsoft SQL Server 2012 Dialect
*
@ -65,4 +68,29 @@ public class SQLServer2012Dialect extends SQLServer2008Dialect {
public String getQuerySequencesString() {
return "select name from sys.sequences";
}
@Override
public String getQueryHintString(String sql, List<String> hints) {
final String hint = StringHelper.join(", ", hints.iterator());
if (StringHelper.isEmpty(hint)) {
return sql;
}
final StringBuilder buffer = new StringBuilder(sql.length()
+ hint.length() + 12);
final int pos = sql.indexOf(";");
if (pos > -1) {
buffer.append(sql.substring(0, pos));
} else {
buffer.append(sql);
}
buffer.append(" OPTION (").append(hint).append(")");
if (pos > -1) {
buffer.append(";");
}
sql = buffer.toString();
return sql;
}
}

View File

@ -0,0 +1,177 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* JBoss, Home of Professional Open Source
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.hibernate.test.queryhint;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.SQLServer2012Dialect;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
/**
* @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 QueryHintTest$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 QueryHintTest$Employee e WHERE e.department.name = :departmentName" ).addQueryHint( "MAXDOP 2" )
.addQueryHint( "USE_CONCAT" ).setParameter( "departmentName", "Sales" );
results = query.list();
s.getTransaction().commit();
s.clear();
assertEquals( results.size(), 2 );
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "OPTION (MAXDOP 2)" ) );
QueryHintTestSQLServer2012Dialect.resetProcessedSql();
// ensure the insertion logic can handle a comment appended to the front
s.getTransaction().begin();
query = s.createQuery( "FROM QueryHintTest$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();
Criteria criteria = s.createCriteria( Employee.class ).addQueryHint( "MAXDOP 2" ).createCriteria( "department" )
.add( Restrictions.eq( "name", "Sales" ) );
results = criteria.list();
s.getTransaction().commit();
s.close();
assertEquals( results.size(), 2 );
assertTrue( QueryHintTestSQLServer2012Dialect.getProcessedSql().contains( "OPTION (MAXDOP 2)" ) );
assertEquals( false, true );
}
/**
* 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;
}
}