diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2008Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2008Dialect.java index 0fea3f849e..3822b6fd70 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2008Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2008Dialect.java @@ -8,6 +8,7 @@ package org.hibernate.dialect; import java.sql.Types; +import org.hibernate.NullPrecedence; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.type.StandardBasicTypes; @@ -29,4 +30,26 @@ public class SQLServer2008Dialect extends SQLServer2005Dialect { "current_timestamp", new NoArgSQLFunction( "current_timestamp", StandardBasicTypes.TIMESTAMP, false ) ); } + + @Override + public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nulls) { + final StringBuilder orderByElement = new StringBuilder(); + + if ( nulls != null && !NullPrecedence.NONE.equals( nulls ) ) { + // Workaround for NULLS FIRST / LAST support. + orderByElement.append( "case when " ).append( expression ).append( " is null then " ); + if ( NullPrecedence.FIRST.equals( nulls ) ) { + orderByElement.append( "0 else 1" ); + } + else { + orderByElement.append( "1 else 0" ); + } + orderByElement.append( " end, " ); + } + + // Nulls precedence has already been handled so passing NONE value. + orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) ); + + return orderByElement.toString(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 2fbd7d51c1..7374bf3f3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -203,5 +203,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { public int getInExpressionCountLimit() { return PARAM_LIST_SIZE_LIMIT; } + } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/onetomany/OrderByTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/onetomany/OrderByTest.java index b678d7560f..0c99517b3a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/onetomany/OrderByTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/onetomany/OrderByTest.java @@ -26,6 +26,9 @@ import org.hibernate.Session; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.Oracle8iDialect; +import org.hibernate.dialect.SQLServer2008Dialect; +import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.dialect.SQLServerDialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.QueryableCollection; @@ -80,10 +83,10 @@ public class OrderByTest extends BaseCoreFunctionalTestCase { @Test @TestForIssue(jiraKey = "HHH-465") - @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class }, + @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class, SQLServer2008Dialect.class }, comment = "By default H2 places NULL values first, so testing 'NULLS LAST' expression. " + - "For MySQL testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + - "MySQL does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") + "For MySQL and SQL Server 2008 testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + + "MySQL and SQLServer 2008 does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") public void testAnnotationNullsFirstLast() { Session session = openSession(); @@ -139,10 +142,10 @@ public class OrderByTest extends BaseCoreFunctionalTestCase { @Test @TestForIssue(jiraKey = "HHH-465") - @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class }, + @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class, SQLServer2008Dialect.class }, comment = "By default H2 places NULL values first, so testing 'NULLS LAST' expression. " + - "For MySQL testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + - "MySQL does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") + "For MySQL and SQL Server 2008 testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + + "MySQL and SQL Server 2008 does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") public void testCriteriaNullsFirstLast() { Session session = openSession(); @@ -177,10 +180,10 @@ public class OrderByTest extends BaseCoreFunctionalTestCase { @Test @TestForIssue(jiraKey = "HHH-465") - @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class }, + @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class, SQLServer2008Dialect.class }, comment = "By default H2 places NULL values first, so testing 'NULLS LAST' expression. " + - "For MySQL testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + - "MySQL does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") + "For MySQL and SQL Server 2008 testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + + "MySQL and SQL Server 2008 does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") public void testNullsFirstLastSpawnMultipleColumns() { Session session = openSession(); @@ -226,10 +229,10 @@ public class OrderByTest extends BaseCoreFunctionalTestCase { @Test @TestForIssue(jiraKey = "HHH-465") - @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class }, + @RequiresDialect(value = { H2Dialect.class, MySQLDialect.class, SQLServer2008Dialect.class }, comment = "By default H2 places NULL values first, so testing 'NULLS LAST' expression. " + - "For MySQL testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + - "MySQL does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") + "For MySQL and SQL Server 2008 testing overridden Dialect#renderOrderByElement(String, String, String, NullPrecedence) method. " + + "MySQL and SQL Server 2008 does not support NULLS FIRST / LAST syntax at the moment, so transforming the expression to 'CASE WHEN ...'.") public void testHqlNullsFirstLast() { Session session = openSession();