HHH-15928 Check distinct and sub-queries for SQLServer fetch / offset
This commit is contained in:
parent
21d7d2bb10
commit
b5d58e69ae
|
@ -11,16 +11,15 @@ import java.util.List;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.dialect.DatabaseVersion;
|
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.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||||
import org.hibernate.query.sqm.ComparisonOperator;
|
import org.hibernate.query.sqm.ComparisonOperator;
|
||||||
|
import org.hibernate.query.sqm.FetchClauseType;
|
||||||
import org.hibernate.sql.ast.Clause;
|
import org.hibernate.sql.ast.Clause;
|
||||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.Statement;
|
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.BinaryArithmeticExpression;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||||
|
@ -252,6 +251,10 @@ public class SQLServerLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
|
||||||
else if ( version.isBefore( 11 ) || !isRowsOnlyFetchClauseType( queryPart ) ) {
|
else if ( version.isBefore( 11 ) || !isRowsOnlyFetchClauseType( queryPart ) ) {
|
||||||
return OffsetFetchClauseMode.EMULATED;
|
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 {
|
else {
|
||||||
return OffsetFetchClauseMode.STANDARD;
|
return OffsetFetchClauseMode.STANDARD;
|
||||||
}
|
}
|
||||||
|
@ -310,14 +313,6 @@ public class SQLServerLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
|
||||||
return getDialect().getVersion().isBefore( 9 );
|
return getDialect().getVersion().isBefore( 9 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderFetchPlusOffsetExpression(
|
|
||||||
Expression fetchClauseExpression,
|
|
||||||
Expression offsetClauseExpression,
|
|
||||||
int offset) {
|
|
||||||
renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void visitSqlSelections(SelectClause selectClause) {
|
protected void visitSqlSelections(SelectClause selectClause) {
|
||||||
final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent();
|
final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent();
|
||||||
|
@ -346,7 +341,7 @@ public class SQLServerLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
|
||||||
|
|
||||||
protected void renderEmptyOrderBy() {
|
protected void renderEmptyOrderBy() {
|
||||||
// Always need an order by clause: https://blog.jooq.org/2014/05/13/sql-server-trick-circumvent-missing-order-by-clause/
|
// 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
|
@Override
|
||||||
|
@ -355,7 +350,6 @@ public class SQLServerLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
|
||||||
if ( getDialect().getVersion().isBefore( 9 ) && !queryPart.isRoot() && queryPart.getOffsetClauseExpression() != null ) {
|
if ( getDialect().getVersion().isBefore( 9 ) && !queryPart.isRoot() && queryPart.getOffsetClauseExpression() != null ) {
|
||||||
throw new IllegalArgumentException( "Can't emulate offset clause in subquery" );
|
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 );
|
final OffsetFetchClauseMode offsetFetchClauseMode = getOffsetFetchClauseMode( queryPart );
|
||||||
if ( offsetFetchClauseMode == OffsetFetchClauseMode.STANDARD ) {
|
if ( offsetFetchClauseMode == OffsetFetchClauseMode.STANDARD ) {
|
||||||
if ( !queryPart.hasSortSpecifications() ) {
|
if ( !queryPart.hasSortSpecifications() ) {
|
||||||
|
@ -387,10 +381,6 @@ public class SQLServerLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
|
||||||
renderFetch( fetchExpression, null, fetchClauseType );
|
renderFetch( fetchExpression, null, fetchClauseType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( offsetFetchClauseMode == OffsetFetchClauseMode.TOP_ONLY && !queryPart.hasSortSpecifications() ) {
|
|
||||||
appendSql( ' ' );
|
|
||||||
renderEmptyOrderBy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,6 +230,10 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
||||||
else if ( version.isBefore( 11 ) || !isRowsOnlyFetchClauseType( queryPart ) ) {
|
else if ( version.isBefore( 11 ) || !isRowsOnlyFetchClauseType( queryPart ) ) {
|
||||||
return OffsetFetchClauseMode.EMULATED;
|
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 {
|
else {
|
||||||
return OffsetFetchClauseMode.STANDARD;
|
return OffsetFetchClauseMode.STANDARD;
|
||||||
}
|
}
|
||||||
|
@ -288,14 +292,6 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderFetchPlusOffsetExpression(
|
|
||||||
Expression fetchClauseExpression,
|
|
||||||
Expression offsetClauseExpression,
|
|
||||||
int offset) {
|
|
||||||
renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void visitSqlSelections(SelectClause selectClause) {
|
protected void visitSqlSelections(SelectClause selectClause) {
|
||||||
final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent();
|
final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent();
|
||||||
|
@ -324,13 +320,12 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
||||||
|
|
||||||
protected void renderEmptyOrderBy() {
|
protected void renderEmptyOrderBy() {
|
||||||
// Always need an order by clause: https://blog.jooq.org/2014/05/13/sql-server-trick-circumvent-missing-order-by-clause/
|
// 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
|
@Override
|
||||||
public void visitOffsetFetchClause(QueryPart queryPart) {
|
public void visitOffsetFetchClause(QueryPart queryPart) {
|
||||||
if ( !isRowNumberingCurrentQueryPart() ) {
|
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 );
|
final OffsetFetchClauseMode offsetFetchClauseMode = getOffsetFetchClauseMode( queryPart );
|
||||||
if ( offsetFetchClauseMode == OffsetFetchClauseMode.STANDARD ) {
|
if ( offsetFetchClauseMode == OffsetFetchClauseMode.STANDARD ) {
|
||||||
if ( !queryPart.hasSortSpecifications() ) {
|
if ( !queryPart.hasSortSpecifications() ) {
|
||||||
|
@ -362,10 +357,6 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
||||||
renderFetch( fetchExpression, null, fetchClauseType );
|
renderFetch( fetchExpression, null, fetchClauseType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( offsetFetchClauseMode == OffsetFetchClauseMode.TOP_ONLY && !queryPart.hasSortSpecifications() ) {
|
|
||||||
appendSql( ' ' );
|
|
||||||
renderEmptyOrderBy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue