From b5d58e69ae30b1875fad6e897a7f8dcc4f37808c Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Wed, 11 Jan 2023 13:02:53 +0100 Subject: [PATCH] HHH-15928 Check distinct and sub-queries for SQLServer fetch / offset --- .../SQLServerLegacySqlAstTranslator.java | 24 ++++++------------- .../dialect/SQLServerSqlAstTranslator.java | 19 ++++----------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java index 4d3d1c37ff..7171b4710a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java @@ -11,16 +11,15 @@ import java.util.List; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.dialect.DatabaseVersion; -import org.hibernate.metamodel.mapping.JdbcMappingContainer; -import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.query.sqm.ComparisonOperator; +import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; -import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; @@ -252,6 +251,10 @@ public class SQLServerLegacySqlAstTranslator extends Ab else if ( version.isBefore( 11 ) || !isRowsOnlyFetchClauseType( queryPart ) ) { return OffsetFetchClauseMode.EMULATED; } + else if ( !queryPart.hasSortSpecifications() && ((QuerySpec) queryPart).getSelectClause().isDistinct() ) { + // order by (select 0) workaround for offset / fetch does not work when query is distinct + return OffsetFetchClauseMode.EMULATED; + } else { return OffsetFetchClauseMode.STANDARD; } @@ -310,14 +313,6 @@ public class SQLServerLegacySqlAstTranslator extends Ab return getDialect().getVersion().isBefore( 9 ); } - @Override - protected void renderFetchPlusOffsetExpression( - Expression fetchClauseExpression, - Expression offsetClauseExpression, - int offset) { - renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, offset ); - } - @Override protected void visitSqlSelections(SelectClause selectClause) { final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent(); @@ -346,7 +341,7 @@ public class SQLServerLegacySqlAstTranslator extends Ab protected void renderEmptyOrderBy() { // Always need an order by clause: https://blog.jooq.org/2014/05/13/sql-server-trick-circumvent-missing-order-by-clause/ - appendSql( "order by @@version" ); + appendSql( "order by (select 0)" ); } @Override @@ -355,7 +350,6 @@ public class SQLServerLegacySqlAstTranslator extends Ab if ( getDialect().getVersion().isBefore( 9 ) && !queryPart.isRoot() && queryPart.getOffsetClauseExpression() != null ) { throw new IllegalArgumentException( "Can't emulate offset clause in subquery" ); } - // Note that SQL Server is very strict i.e. it requires an order by clause for TOP or OFFSET final OffsetFetchClauseMode offsetFetchClauseMode = getOffsetFetchClauseMode( queryPart ); if ( offsetFetchClauseMode == OffsetFetchClauseMode.STANDARD ) { if ( !queryPart.hasSortSpecifications() ) { @@ -387,10 +381,6 @@ public class SQLServerLegacySqlAstTranslator extends Ab renderFetch( fetchExpression, null, fetchClauseType ); } } - else if ( offsetFetchClauseMode == OffsetFetchClauseMode.TOP_ONLY && !queryPart.hasSortSpecifications() ) { - appendSql( ' ' ); - renderEmptyOrderBy(); - } } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java index ec567e76ed..299ca276b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java @@ -230,6 +230,10 @@ public class SQLServerSqlAstTranslator extends Abstract else if ( version.isBefore( 11 ) || !isRowsOnlyFetchClauseType( queryPart ) ) { return OffsetFetchClauseMode.EMULATED; } + else if ( !queryPart.hasSortSpecifications() && ((QuerySpec) queryPart).getSelectClause().isDistinct() ) { + // order by (select 0) workaround for offset / fetch does not work when query is distinct + return OffsetFetchClauseMode.EMULATED; + } else { return OffsetFetchClauseMode.STANDARD; } @@ -288,14 +292,6 @@ public class SQLServerSqlAstTranslator extends Abstract return false; } - @Override - protected void renderFetchPlusOffsetExpression( - Expression fetchClauseExpression, - Expression offsetClauseExpression, - int offset) { - renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, offset ); - } - @Override protected void visitSqlSelections(SelectClause selectClause) { final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent(); @@ -324,13 +320,12 @@ public class SQLServerSqlAstTranslator extends Abstract protected void renderEmptyOrderBy() { // Always need an order by clause: https://blog.jooq.org/2014/05/13/sql-server-trick-circumvent-missing-order-by-clause/ - appendSql( "order by @@version" ); + appendSql( "order by (select 0)" ); } @Override public void visitOffsetFetchClause(QueryPart queryPart) { if ( !isRowNumberingCurrentQueryPart() ) { - // Note that SQL Server is very strict i.e. it requires an order by clause for TOP or OFFSET final OffsetFetchClauseMode offsetFetchClauseMode = getOffsetFetchClauseMode( queryPart ); if ( offsetFetchClauseMode == OffsetFetchClauseMode.STANDARD ) { if ( !queryPart.hasSortSpecifications() ) { @@ -362,10 +357,6 @@ public class SQLServerSqlAstTranslator extends Abstract renderFetch( fetchExpression, null, fetchClauseType ); } } - else if ( offsetFetchClauseMode == OffsetFetchClauseMode.TOP_ONLY && !queryPart.hasSortSpecifications() ) { - appendSql( ' ' ); - renderEmptyOrderBy(); - } } }