diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 index d18a924a5..4ed7a4455 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 @@ -85,7 +85,7 @@ cteAttributes ; orderedQuery - : (query | '(' queryExpression ')') queryOrder? + : (query | '(' queryExpression ')') queryOrder? limitClause? offsetClause? fetchClause? ; query @@ -94,7 +94,7 @@ query ; queryOrder - : orderByClause limitClause? offsetClause? fetchClause? + : orderByClause ; fromClause diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java index f310630d7..00417913e 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlCountQueryTransformer.java @@ -60,8 +60,16 @@ class HqlCountQueryTransformer extends HqlQueryRenderer { builder.appendExpression(nested); } - if (ctx.queryOrder() != null) { - builder.append(visit(ctx.queryOrder())); + if (ctx.limitClause() != null) { + builder.appendExpression(visit(ctx.limitClause())); + } + + if (ctx.offsetClause() != null) { + builder.appendExpression(visit(ctx.offsetClause())); + } + + if (ctx.fetchClause() != null) { + builder.appendExpression(visit(ctx.fetchClause())); } return builder; @@ -240,26 +248,6 @@ class HqlCountQueryTransformer extends HqlQueryRenderer { return builder; } - @Override - public QueryRendererBuilder visitQueryOrder(HqlParser.QueryOrderContext ctx) { - - QueryRendererBuilder builder = QueryRenderer.builder(); - - if (ctx.limitClause() != null) { - builder.appendExpression(visit(ctx.limitClause())); - } - - if (ctx.offsetClause() != null) { - builder.appendExpression(visit(ctx.offsetClause())); - } - - if (ctx.fetchClause() != null) { - builder.appendExpression(visit(ctx.fetchClause())); - } - - return builder; - } - private QueryRendererBuilder visitSubQuerySelectClause(SelectClauseContext ctx, QueryRendererBuilder builder) { if (ctx.DISTINCT() != null) { diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java index 36f8a2f62..6b1bf850e 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java @@ -239,6 +239,18 @@ class HqlQueryRenderer extends HqlBaseVisitor { builder.append(visit(ctx.queryOrder())); } + if (ctx.limitClause() != null) { + builder.appendExpression(visit(ctx.limitClause())); + } + + if (ctx.offsetClause() != null) { + builder.appendExpression(visit(ctx.offsetClause())); + } + + if (ctx.fetchClause() != null) { + builder.appendExpression(visit(ctx.fetchClause())); + } + return builder; } @@ -298,26 +310,7 @@ class HqlQueryRenderer extends HqlBaseVisitor { @Override public QueryTokenStream visitQueryOrder(HqlParser.QueryOrderContext ctx) { - - if (ctx.limitClause() == null && ctx.offsetClause() == null && ctx.fetchClause() == null) { - return visit(ctx.orderByClause()); - } - - QueryRendererBuilder builder = QueryRenderer.builder(); - - builder.appendExpression(visit(ctx.orderByClause())); - - if (ctx.limitClause() != null) { - builder.appendExpression(visit(ctx.limitClause())); - } - if (ctx.offsetClause() != null) { - builder.appendExpression(visit(ctx.offsetClause())); - } - if (ctx.fetchClause() != null) { - builder.appendExpression(visit(ctx.fetchClause())); - } - - return builder; + return visit(ctx.orderByClause()); } @Override diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlSortedQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlSortedQueryTransformer.java index 718a813d3..21c225d5b 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlSortedQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlSortedQueryTransformer.java @@ -162,6 +162,18 @@ class HqlSortedQueryTransformer extends HqlQueryRenderer { } } + if (ctx.limitClause() != null) { + builder.appendExpression(visit(ctx.limitClause())); + } + + if (ctx.offsetClause() != null) { + builder.appendExpression(visit(ctx.offsetClause())); + } + + if (ctx.fetchClause() != null) { + builder.appendExpression(visit(ctx.fetchClause())); + } + return builder; } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java index 78693498c..6abc8b504 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java @@ -1676,6 +1676,20 @@ class HqlQueryRendererTests { }); } + @Test // GH-3882 + void shouldSupportLimitOffset() { + + assertQuery("SELECT si from StockItem si order by si.id LIMIT 10 OFFSET 10 FETCH FIRST 10 ROWS ONLY"); + assertQuery("SELECT si from StockItem si order by si.id LIMIT ? OFFSET ? FETCH FIRST ? ROWS ONLY"); + assertQuery("SELECT si from StockItem si order by si.id LIMIT :l OFFSET :o"); + assertQuery("SELECT si from StockItem si LIMIT :l OFFSET :o"); + assertQuery("SELECT si from StockItem si order by si.id LIMIT :l"); + assertQuery("SELECT si from StockItem si order by si.id OFFSET 1"); + assertQuery("SELECT si from StockItem si LIMIT 1"); + assertQuery("SELECT si from StockItem si OFFSET 1"); + assertQuery("SELECT si from StockItem si FETCH FIRST 1 ROWS ONLY"); + } + @Test // GH-2964 void roundFunctionShouldWorkLikeAnyOtherFunction() {