Skip to content

Commit 0a5a56f

Browse files
mp911dechristophstrobl
authored andcommitted
Optimize QueryTokenStream handling.
This commit moves EQL and HQL parsers to QueryTokenStream and optimizes composite renderers as well as JSQLParser usage. We also avoid Single-thread construction on each parse run to avoid thread creation overhead. See: #3309
1 parent f793c9e commit 0a5a56f

34 files changed

+2043
-1578
lines changed

spring-data-jpa-performance/src/test/java/org/springframework/data/jpa/repository/Profiler.java

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.repository.query;
17+
18+
import java.util.Collections;
19+
import java.util.Iterator;
20+
21+
/**
22+
* Empty QueryTokenStream.
23+
*
24+
* @author Mark Paluch
25+
* @since 3.4
26+
*/
27+
class EmptyQueryTokenStream implements QueryTokenStream {
28+
29+
static final EmptyQueryTokenStream INSTANCE = new EmptyQueryTokenStream();
30+
31+
private EmptyQueryTokenStream() {}
32+
33+
@Override
34+
public QueryToken getFirst() {
35+
return null;
36+
}
37+
38+
@Override
39+
public QueryToken getLast() {
40+
return null;
41+
}
42+
43+
@Override
44+
public boolean isExpression() {
45+
return false;
46+
}
47+
48+
@Override
49+
public int size() {
50+
return 0;
51+
}
52+
53+
@Override
54+
public boolean isEmpty() {
55+
return true;
56+
}
57+
58+
@Override
59+
public Iterator<QueryToken> iterator() {
60+
return Collections.emptyIterator();
61+
}
62+
}

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package org.springframework.data.jpa.repository.query;
1717

18-
import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*;
18+
import static org.springframework.data.jpa.repository.query.QueryTokens.*;
1919

2020
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
2121
import org.springframework.data.jpa.repository.query.QueryTransformers.CountSelectionTokenStream;
@@ -62,42 +62,42 @@ public QueryRendererBuilder visitSelect_statement(EqlParser.Select_statementCont
6262
}
6363

6464
@Override
65-
public QueryRendererBuilder visitSelect_clause(EqlParser.Select_clauseContext ctx) {
65+
public QueryTokenStream visitSelect_clause(EqlParser.Select_clauseContext ctx) {
6666

6767
QueryRendererBuilder builder = QueryRenderer.builder();
6868

69-
builder.append(JpaQueryParsingToken.expression(ctx.SELECT()));
69+
builder.append(QueryTokens.expression(ctx.SELECT()));
7070
builder.append(TOKEN_COUNT_FUNC);
7171

7272
if (countProjection != null) {
73-
builder.append(JpaQueryParsingToken.token(countProjection));
73+
builder.append(QueryTokens.token(countProjection));
7474
}
7575

7676
QueryRendererBuilder nested = QueryRenderer.builder();
7777

7878
if (ctx.DISTINCT() != null) {
79-
nested.append(JpaQueryParsingToken.expression(ctx.DISTINCT()));
79+
nested.append(QueryTokens.expression(ctx.DISTINCT()));
8080
}
8181

8282
if (countProjection == null) {
8383

8484
if (ctx.DISTINCT() != null) {
8585

86-
QueryRendererBuilder selectionListbuilder = QueryRendererBuilder.concat(ctx.select_item(), this::visit,
86+
QueryTokenStream selectionListbuilder = QueryTokenStream.concat(ctx.select_item(), this::visit,
8787
TOKEN_COMMA);
8888

8989
CountSelectionTokenStream countSelection = QueryTransformers
9090
.filterCountSelection(selectionListbuilder);
9191

9292
if (countSelection.requiresPrimaryAlias()) {
9393
// constructor
94-
nested.append(new JpaQueryParsingToken(primaryFromAlias));
94+
nested.append(QueryTokens.token(primaryFromAlias));
9595
} else {
9696
// keep all the select items to distinct against
9797
nested.append(countSelection);
9898
}
9999
} else {
100-
nested.append(new JpaQueryParsingToken(primaryFromAlias));
100+
nested.append(QueryTokens.token(primaryFromAlias));
101101
}
102102
}
103103

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryIntrospector.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package org.springframework.data.jpa.repository.query;
1717

18-
import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*;
18+
import static org.springframework.data.jpa.repository.query.QueryTokens.*;
1919

2020
import java.util.ArrayList;
2121
import java.util.Collections;
@@ -34,7 +34,7 @@ class EqlQueryIntrospector extends EqlBaseVisitor<Void> implements ParsedQueryIn
3434
private final EqlQueryRenderer renderer = new EqlQueryRenderer();
3535

3636
private @Nullable String primaryFromAlias = null;
37-
private @Nullable List<JpaQueryParsingToken> projection;
37+
private @Nullable List<QueryToken> projection;
3838
private boolean projectionProcessed;
3939
private boolean hasConstructorExpression = false;
4040

@@ -44,7 +44,7 @@ public String getAlias() {
4444
}
4545

4646
@Override
47-
public List<JpaQueryParsingToken> getProjection() {
47+
public List<QueryToken> getProjection() {
4848
return projection == null ? Collections.emptyList() : projection;
4949
}
5050

@@ -57,15 +57,15 @@ public boolean hasConstructorExpression() {
5757
public Void visitSelect_clause(EqlParser.Select_clauseContext ctx) {
5858

5959
List<EqlParser.Select_itemContext> selections = ctx.select_item();
60-
List<JpaQueryParsingToken> selectItemTokens = new ArrayList<>(selections.size() * 2);
60+
List<QueryToken> selectItemTokens = new ArrayList<>(selections.size() * 2);
6161

6262
for (EqlParser.Select_itemContext selection : selections) {
6363

6464
if (!selectItemTokens.isEmpty()) {
6565
selectItemTokens.add(TOKEN_COMMA);
6666
}
6767

68-
selectItemTokens.add(JpaQueryParsingToken.token(renderer.visitSelect_item(selection).build().render()));
68+
selectItemTokens.add(QueryTokens.token(QueryRenderer.from(renderer.visitSelect_item(selection)).render()));
6969
}
7070

7171
if (!projectionProcessed) {

0 commit comments

Comments
 (0)