Skip to content

Commit 703334e

Browse files
committed
Polishing.
Reuse setReturningFunction and genericFunctionArguments structure for easier extension. Split fromRoot into separate parser function fragments. Fix trailing spaces. See: #3864 Original pull request: #3879
1 parent e77bdc6 commit 703334e

File tree

8 files changed

+230
-266
lines changed

8 files changed

+230
-266
lines changed

spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4

+13-13
Original file line numberDiff line numberDiff line change
@@ -112,27 +112,19 @@ joinSpecifier
112112
;
113113

114114
fromRoot
115-
: entityName variable?
116-
| LATERAL? '(' subquery ')' variable?
117-
| functionCallAsFromSource variable?
115+
: entityName variable? # RootEntity
116+
| LATERAL? '(' subquery ')' variable? # RootSubquery
117+
| setReturningFunction variable? # RootFunction
118118
;
119119

120-
functionCallAsFromSource
121-
: identifier '(' (expression (',' expression)*)? ')'
122-
;
123-
124120
join
125121
: joinType JOIN FETCH? joinTarget joinRestriction? // Spec BNF says joinType isn't optional, but text says that it is.
126122
;
127123

128124
joinTarget
129125
: path variable? # JoinPath
130126
| LATERAL? '(' subquery ')' variable? # JoinSubquery
131-
| functionCallAsJoinTarget variable? # JoinFunctionCall
132-
;
133-
134-
functionCallAsJoinTarget
135-
: identifier '(' (expression (',' expression)*)? ')'
127+
| setReturningFunction variable? # JoinFunctionCall
136128
;
137129

138130
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-update
@@ -768,6 +760,14 @@ function
768760
| genericFunction # GenericFunctionInvocation
769761
;
770762

763+
setReturningFunction
764+
: simpleSetReturningFunction
765+
;
766+
767+
simpleSetReturningFunction
768+
: identifier '(' genericFunctionArguments? ')'
769+
;
770+
771771
/**
772772
* Any function with an irregular syntax for the argument list
773773
*
@@ -1888,4 +1888,4 @@ ESCAPE_SEQUENCE
18881888
18891889
QUOTED_IDENTIFIER
18901890
: BACKTICK ( ESCAPE_SEQUENCE | '\\' BACKTICK | ~([`]) )* BACKTICK
1891-
;
1891+
;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* Hibernate-specific query details capturing common table expression details.
2424
*
2525
* @author Mark Paluch
26-
* @author oscar.fanchin
26+
* @author Oscar Fanchin
2727
* @since 3.5
2828
*/
2929
class HibernateQueryInformation extends QueryInformation {

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

+2-44
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* @author Greg Turnquist
3131
* @author Christoph Strobl
3232
* @author Mark Paluch
33-
* @author oscar.fanchin
33+
* @author Oscar Fanchin
3434
* @since 3.1
3535
*/
3636
@SuppressWarnings("ConstantValue")
@@ -113,7 +113,6 @@ public QueryRendererBuilder visitFromQuery(HqlParser.FromQueryContext ctx) {
113113
}
114114
}
115115

116-
117116
if (ctx.whereClause() != null) {
118117
builder.appendExpression(visit(ctx.whereClause()));
119118
}
@@ -133,48 +132,6 @@ public QueryRendererBuilder visitFromQuery(HqlParser.FromQueryContext ctx) {
133132
return builder;
134133
}
135134

136-
@Override
137-
public QueryRendererBuilder visitFromRoot(HqlParser.FromRootContext ctx) {
138-
139-
QueryRendererBuilder builder = QueryRenderer.builder();
140-
141-
if (ctx.entityName() != null) {
142-
143-
builder.appendExpression(visit(ctx.entityName()));
144-
145-
if (ctx.variable() != null) {
146-
builder.appendExpression(visit(ctx.variable()));
147-
}
148-
} else if (ctx.subquery() != null) {
149-
150-
if (ctx.LATERAL() != null) {
151-
builder.append(QueryTokens.expression(ctx.LATERAL()));
152-
}
153-
154-
QueryRendererBuilder nested = QueryRenderer.builder();
155-
156-
nested.append(TOKEN_OPEN_PAREN);
157-
nested.appendInline(visit(ctx.subquery()));
158-
nested.append(TOKEN_CLOSE_PAREN);
159-
160-
builder.appendExpression(nested);
161-
162-
if (ctx.variable() != null) {
163-
builder.appendExpression(visit(ctx.variable()));
164-
}
165-
} else if (ctx.functionCallAsFromSource() != null) {
166-
167-
builder.appendExpression(visit(ctx.functionCallAsFromSource()));
168-
169-
if (ctx.variable() != null) {
170-
builder.appendExpression(visit(ctx.variable()));
171-
}
172-
}
173-
174-
175-
return builder;
176-
}
177-
178135
@Override
179136
public QueryRendererBuilder visitJoin(HqlParser.JoinContext ctx) {
180137

@@ -193,6 +150,7 @@ public QueryRendererBuilder visitJoin(HqlParser.JoinContext ctx) {
193150
return builder;
194151
}
195152

153+
196154
@Override
197155
public QueryTokenStream visitSelectClause(HqlParser.SelectClauseContext ctx) {
198156

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

+29-14
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
import java.util.Collections;
2222
import java.util.List;
2323

24-
import org.springframework.data.jpa.repository.query.HqlParser.VariableContext;
25-
2624
import org.jspecify.annotations.Nullable;
2725

26+
import org.springframework.data.jpa.repository.query.HqlParser.VariableContext;
27+
2828
/**
2929
* {@link ParsedQueryIntrospector} for HQL queries.
3030
*
3131
* @author Mark Paluch
32-
* @author oscar.fanchin
32+
* @author Oscar Fanchin
3333
*/
3434
@SuppressWarnings({ "UnreachableCode", "ConstantValue" })
3535
class HqlQueryIntrospector extends HqlBaseVisitor<Void> implements ParsedQueryIntrospector<HibernateQueryInformation> {
@@ -52,9 +52,9 @@ public HibernateQueryInformation getParsedQueryInformation() {
5252
@Override
5353
public Void visitSelectClause(HqlParser.SelectClauseContext ctx) {
5454

55-
if (!projectionProcessed) {
56-
projection = captureSelectItems(ctx.selectionList().selection(), renderer);
57-
projectionProcessed = true;
55+
if (!this.projectionProcessed) {
56+
this.projection = captureSelectItems(ctx.selectionList().selection(), renderer);
57+
this.projectionProcessed = true;
5858
}
5959

6060
return super.visitSelectClause(ctx);
@@ -65,21 +65,36 @@ public Void visitCte(HqlParser.CteContext ctx) {
6565
this.hasCte = true;
6666
return super.visitCte(ctx);
6767
}
68-
68+
69+
@Override
70+
public Void visitRootEntity(HqlParser.RootEntityContext ctx) {
71+
72+
if (this.primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
73+
this.primaryFromAlias = capturePrimaryAlias(ctx.variable());
74+
}
75+
76+
return super.visitRootEntity(ctx);
77+
}
78+
6979
@Override
70-
public Void visitFunctionCallAsFromSource(HqlParser.FunctionCallAsFromSourceContext ctx) {
71-
this.hasFromFunction = true;
72-
return super.visitFunctionCallAsFromSource(ctx);
80+
public Void visitRootSubquery(HqlParser.RootSubqueryContext ctx) {
81+
82+
if (this.primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
83+
this.primaryFromAlias = capturePrimaryAlias(ctx.variable());
84+
}
85+
86+
return super.visitRootSubquery(ctx);
7387
}
7488

7589
@Override
76-
public Void visitFromRoot(HqlParser.FromRootContext ctx) {
90+
public Void visitRootFunction(HqlParser.RootFunctionContext ctx) {
7791

78-
if (primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
79-
primaryFromAlias = capturePrimaryAlias(ctx.variable());
92+
if (this.primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
93+
this.primaryFromAlias = capturePrimaryAlias(ctx.variable());
94+
this.hasFromFunction = true;
8095
}
8196

82-
return super.visitFromRoot(ctx);
97+
return super.visitRootFunction(ctx);
8398
}
8499

85100
@Override

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

+55-61
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,6 @@ public QueryTokenStream visitStart(HqlParser.StartContext ctx) {
6464
return visit(ctx.ql_statement());
6565
}
6666

67-
@Override
68-
public QueryTokenStream visitFunctionCallAsFromSource(HqlParser.FunctionCallAsFromSourceContext ctx) {
69-
70-
QueryRendererBuilder builder = QueryRenderer.builder();
71-
72-
builder.append(visit(ctx.identifier()));
73-
74-
builder.append(TOKEN_OPEN_PAREN);
75-
76-
if (!ctx.expression().isEmpty()) {
77-
builder.append(QueryTokenStream.concatExpressions(ctx.expression(), this::visit, TOKEN_COMMA));
78-
}
79-
80-
builder.append(TOKEN_CLOSE_PAREN);
81-
82-
return builder;
83-
}
84-
8567
@Override
8668
public QueryTokenStream visitQl_statement(HqlParser.Ql_statementContext ctx) {
8769

@@ -369,44 +351,74 @@ public QueryTokenStream visitJoinSpecifier(HqlParser.JoinSpecifierContext ctx) {
369351
}
370352

371353
@Override
372-
public QueryTokenStream visitFromRoot(HqlParser.FromRootContext ctx) {
354+
public QueryTokenStream visitRootEntity(HqlParser.RootEntityContext ctx) {
373355

374356
QueryRendererBuilder builder = QueryRenderer.builder();
375357

376-
if (ctx.entityName() != null) {
358+
builder.appendExpression(visit(ctx.entityName()));
377359

378-
builder.appendExpression(visit(ctx.entityName()));
360+
if (ctx.variable() != null) {
361+
builder.appendExpression(visit(ctx.variable()));
362+
}
379363

380-
if (ctx.variable() != null) {
381-
builder.appendExpression(visit(ctx.variable()));
382-
}
364+
return builder;
365+
}
383366

384-
} else if (ctx.subquery() != null) {
367+
@Override
368+
public QueryTokenStream visitRootSubquery(HqlParser.RootSubqueryContext ctx) {
385369

386-
if (ctx.LATERAL() != null) {
387-
builder.append(QueryTokens.expression(ctx.LATERAL()));
388-
}
370+
QueryRendererBuilder builder = QueryRenderer.builder();
389371

390-
QueryRendererBuilder nested = QueryRenderer.builder();
372+
if (ctx.LATERAL() != null) {
373+
builder.append(QueryTokens.expression(ctx.LATERAL()));
374+
}
391375

392-
nested.append(TOKEN_OPEN_PAREN);
393-
nested.appendInline(visit(ctx.subquery()));
394-
nested.append(TOKEN_CLOSE_PAREN);
376+
QueryRendererBuilder nested = QueryRenderer.builder();
395377

396-
builder.appendExpression(nested);
378+
nested.append(TOKEN_OPEN_PAREN);
379+
nested.appendInline(visit(ctx.subquery()));
380+
nested.append(TOKEN_CLOSE_PAREN);
397381

398-
if (ctx.variable() != null) {
399-
builder.appendExpression(visit(ctx.variable()));
400-
}
382+
builder.appendExpression(nested);
401383

402-
} else if (ctx.functionCallAsFromSource() != null) {
384+
if (ctx.variable() != null) {
385+
builder.appendExpression(visit(ctx.variable()));
386+
}
403387

404-
builder.appendExpression(visit(ctx.functionCallAsFromSource()));
388+
return builder;
389+
}
405390

406-
if (ctx.variable() != null) {
407-
builder.appendExpression(visit(ctx.variable()));
408-
}
391+
@Override
392+
public QueryTokenStream visitRootFunction(HqlParser.RootFunctionContext ctx) {
393+
394+
QueryRendererBuilder builder = QueryRenderer.builder();
395+
396+
builder.appendExpression(visit(ctx.setReturningFunction()));
397+
398+
if (ctx.variable() != null) {
399+
builder.appendExpression(visit(ctx.variable()));
400+
}
401+
402+
return builder;
403+
}
404+
405+
@Override
406+
public QueryTokenStream visitSetReturningFunction(HqlParser.SetReturningFunctionContext ctx) {
407+
return visit(ctx.simpleSetReturningFunction());
408+
}
409+
410+
@Override
411+
public QueryTokenStream visitSimpleSetReturningFunction(HqlParser.SimpleSetReturningFunctionContext ctx) {
412+
413+
QueryRendererBuilder builder = QueryRenderer.builder();
414+
415+
builder.append(visit(ctx.identifier()));
416+
417+
builder.append(TOKEN_OPEN_PAREN);
418+
if (ctx.genericFunctionArguments() != null) {
419+
builder.append(visit(ctx.genericFunctionArguments()));
409420
}
421+
builder.append(TOKEN_CLOSE_PAREN);
410422

411423
return builder;
412424
}
@@ -459,7 +471,7 @@ public QueryTokenStream visitJoinSubquery(HqlParser.JoinSubqueryContext ctx) {
459471
}
460472

461473
builder.append(TOKEN_OPEN_PAREN);
462-
builder.append(visit(ctx.subquery()));
474+
builder.appendInline(visit(ctx.subquery()));
463475
builder.append(TOKEN_CLOSE_PAREN);
464476

465477
if (ctx.variable() != null) {
@@ -474,7 +486,7 @@ public QueryTokenStream visitJoinFunctionCall(HqlParser.JoinFunctionCallContext
474486

475487
QueryRendererBuilder builder = QueryRenderer.builder();
476488

477-
builder.append(visit(ctx.functionCallAsJoinTarget()));
489+
builder.append(visit(ctx.setReturningFunction()));
478490

479491
if (ctx.variable() != null) {
480492
builder.appendExpression(visit(ctx.variable()));
@@ -484,24 +496,6 @@ public QueryTokenStream visitJoinFunctionCall(HqlParser.JoinFunctionCallContext
484496

485497
}
486498

487-
@Override
488-
public QueryTokenStream visitFunctionCallAsJoinTarget(HqlParser.FunctionCallAsJoinTargetContext ctx) {
489-
490-
QueryRendererBuilder builder = QueryRenderer.builder();
491-
492-
builder.append(visit(ctx.identifier()));
493-
494-
builder.append(TOKEN_OPEN_PAREN);
495-
496-
if (!ctx.expression().isEmpty()) {
497-
builder.append(QueryTokenStream.concatExpressions(ctx.expression(), this::visit, TOKEN_COMMA));
498-
}
499-
500-
builder.append(TOKEN_CLOSE_PAREN);
501-
502-
return builder;
503-
}
504-
505499
@Override
506500
public QueryTokenStream visitUpdateStatement(HqlParser.UpdateStatementContext ctx) {
507501

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
*
3333
* @author Greg Turnquist
3434
* @author Christoph Strobl
35-
* @author oscar.fanchin
35+
* @author Oscar Fanchin
3636
* @since 3.1
3737
*/
3838
@SuppressWarnings("ConstantValue")

0 commit comments

Comments
 (0)