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 ca7d29befd..8b88a386a5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -38,6 +38,7 @@ import org.hibernate.type.StandardBasicTypes; */ public class SQLServerDialect extends AbstractTransactSQLDialect { private static final String SELECT = "select"; + private static final String FROM = "from"; private static final String DISTINCT = "distinct"; @@ -79,10 +80,8 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { *
 	 * WITH query AS (SELECT ROW_NUMBER() OVER (ORDER BY orderby) as __hibernate_row_nr__, original_query_without_orderby)
 	 * SELECT * FROM query WHERE __hibernate_row_nr__ BEETWIN offset AND offset + last
-	 * --ORDER BY __hibernate_row_nr__
 	 * 
* - * I don't think that the last order by clause is mandatory * * @param querySqlString The SQL statement to base the limit query off of. * @param offset Offset of the first row to be returned by the query (zero-based) @@ -108,43 +107,68 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { sb.delete( orderByIndex, orderByIndex + orderby.length() ); } + // HHH-5715 bug fix replaceDistinctWithGroupBy( sb ); - insertRowNumberFunction(sb, orderby); + insertRowNumberFunction( sb, orderby ); //Wrap the query within a with statement: - sb.insert(0, "WITH query AS (").append(") SELECT * FROM query "); - sb.append("WHERE __hibernate_row_nr__ BETWEEN ").append(offset + 1).append(" AND ").append(limit); + sb.insert( 0, "WITH query AS (").append(") SELECT * FROM query " ); + sb.append( "WHERE __hibernate_row_nr__ BETWEEN " ).append(offset + 1).append( " AND " ).append( limit ); return sb.toString(); } - protected static void replaceDistinctWithGroupBy(StringBuilder sb) { - int distinctIndex = sb.indexOf( DISTINCT ); + /** + * Utility method that checks if the given sql query is a select distinct one and if so replaces the distinct + * select with an equivelant simple select with a group by clause. See {@link SQLServerDialectTestCase#testReplaceDistinctWithGroupBy()} + * + * @param an sql query + */ + protected static void replaceDistinctWithGroupBy(StringBuilder sql) { + int distinctIndex = sql.indexOf( DISTINCT ); if (distinctIndex > 0) { - - sb.delete(distinctIndex, distinctIndex + DISTINCT.length() + 1); - sb.append(" group by").append(getSelectFieldsWithoutAs(sb)); + sql.delete(distinctIndex, distinctIndex + DISTINCT.length() + 1); + sql.append(" group by").append(getSelectFieldsWithoutAs(sql)); } } + /** + * This utility method searches the given sql query for the fields of the select statement and + * returns them without the as statement. See {@link SQLServerDialectTestCase#testGetSelectFieldsWithoutAs()} + * + * @param an sql query + * @return the fields of the select statement without their alias + */ protected static CharSequence getSelectFieldsWithoutAs(StringBuilder sql) { - String select = sql.substring( sql.indexOf(SELECT) + SELECT.length(), sql.indexOf("from")); + String select = sql.substring( sql.indexOf(SELECT) + SELECT.length(), sql.indexOf(FROM)); // Strip the as clauses - return stripAsStatement(select); + return stripAsStatement( select ); } + /** + * Utility method that strips the as statements. See {@link SQLServerDialectTestCase#testStripAsStatement()} + * + * @param a string to replace the as statements + * @return a string without the as statements + */ protected static String stripAsStatement(String str) { - return str.replaceAll("\\sas[^,]+(,?)", "$1"); + return str.replaceAll( "\\sas[^,]+(,?)", "$1" ); } - protected static void insertRowNumberFunction(StringBuilder sb, CharSequence orderby) { + /** + * Right after the select statement of a given query we must place the row_number function + * + * @param sql the initial sql query without the order by clause + * @param orderby the order by clause of the query + */ + protected static void insertRowNumberFunction(StringBuilder sql, CharSequence orderby) { // Find the end of the select statement - int selectEndIndex = sb.indexOf( SELECT ) + SELECT.length(); + int selectEndIndex = sql.indexOf( SELECT ) + SELECT.length(); // Isert after the select statement the row_number() function: - sb.insert( selectEndIndex, " ROW_NUMBER() OVER (" + orderby + ") as __hibernate_row_nr__," ); + sql.insert( selectEndIndex, " ROW_NUMBER() OVER (" + orderby + ") as __hibernate_row_nr__," ); } /**