Skip to content

Commit dd04ad0

Browse files
christophstroblmp911de
authored andcommitted
Fix EQL parsing for MOD expression.
The samples used to validate MOD parsing in tests does not comply with the specification and falsely uses '/' instead of ',' as delimiter. Definition is: expression ::= MOD(arithmetic_expression, arithmetic_expression) See: https://eclipse.dev/eclipselink/api/4.0/eclipselink/org/eclipse/persistence/jpa/jpql/parser/ModExpression.html Closes #3277 Original pull request: #3280
1 parent ae9b499 commit dd04ad0

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ grammar Eql;
2323
* * https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL
2424
*
2525
* @author Greg Turnquist
26+
* @author Christoph Strobl
2627
* @since 3.2
2728
*/
2829
}
@@ -509,7 +510,7 @@ functions_returning_numerics
509510
| LN '(' arithmetic_expression ')'
510511
| SIGN '(' arithmetic_expression ')'
511512
| SQRT '(' arithmetic_expression ')'
512-
| MOD '(' arithmetic_expression '/' arithmetic_expression ')'
513+
| MOD '(' arithmetic_expression ',' arithmetic_expression ')'
513514
| POWER '(' arithmetic_expression ',' arithmetic_expression ')'
514515
| ROUND '(' arithmetic_expression ',' arithmetic_expression ')'
515516
| SIZE '(' collection_valued_path_expression ')'
@@ -894,4 +895,4 @@ INTLITERAL : ('0' .. '9')+ ;
894895
LONGLITERAL : ('0' .. '9')+ L;
895896
DATELITERAL : '{' D STRINGLITERAL '}';
896897
TIMELITERAL : '{' T STRINGLITERAL '}';
897-
TIMESTAMPLITERAL : '{' T S STRINGLITERAL '}';
898+
TIMESTAMPLITERAL : '{' T S STRINGLITERAL '}';

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders an EQL query without making any changes.
2525
*
2626
* @author Greg Turnquist
27+
* @author Christoph Strobl
2728
* @since 3.2
2829
*/
2930
@SuppressWarnings({ "ConstantConditions", "DuplicatedCode" })
@@ -1912,7 +1913,8 @@ public List<JpaQueryParsingToken> visitFunctions_returning_numerics(
19121913
tokens.add(new JpaQueryParsingToken(ctx.MOD(), false));
19131914
tokens.add(TOKEN_OPEN_PAREN);
19141915
tokens.addAll(visit(ctx.arithmetic_expression(0)));
1915-
tokens.add(new JpaQueryParsingToken("/"));
1916+
NOSPACE(tokens);
1917+
tokens.add(TOKEN_COMMA);
19161918
tokens.addAll(visit(ctx.arithmetic_expression(1)));
19171919
NOSPACE(tokens);
19181920
tokens.add(TOKEN_CLOSE_PAREN);

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@
2525
/**
2626
* Tests built around examples of EQL found in the EclipseLink's docs at
2727
* https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL<br/>
28+
* With the exception of {@literal MOD} which is defined as {@literal MOD(arithmetic_expression , arithmetic_expression)},
29+
* but shown in tests as {@literal MOD(arithmetic_expression ? arithmetic_expression)}.
2830
* <br/>
2931
* IMPORTANT: Purely verifies the parser without any transformations.
3032
*
3133
* @author Greg Turnquist
34+
* @author Christoph Strobl
3235
*/
3336
class EqlComplianceTests {
3437

@@ -214,7 +217,7 @@ void functionsInSelect() {
214217
assertQuery("SELECT e.name, CURRENT_TIMESTAMP FROM Employee e");
215218
assertQuery("SELECT LENGTH(e.lastName) FROM Employee e");
216219
assertQuery("SELECT LOWER(e.lastName) FROM Employee e");
217-
assertQuery("SELECT MOD(e.hoursWorked / 8) FROM Employee e");
220+
assertQuery("SELECT MOD(e.hoursWorked, 8) FROM Employee e");
218221
assertQuery("SELECT NULLIF(e.salary, 0) FROM Employee e");
219222
assertQuery("SELECT SQRT(o.RESULT) FROM Output o");
220223
assertQuery("SELECT SUBSTRING(e.lastName, 0, 2) FROM Employee e");
@@ -243,7 +246,7 @@ void functionsInWhere() {
243246
assertQuery("SELECT e FROM Employee e WHERE CURRENT_TIME > CURRENT_TIMESTAMP");
244247
assertQuery("SELECT e FROM Employee e WHERE LENGTH(e.lastName) > 0");
245248
assertQuery("SELECT e FROM Employee e WHERE LOWER(e.lastName) = 'bilbo'");
246-
assertQuery("SELECT e FROM Employee e WHERE MOD(e.hoursWorked / 8) > 0");
249+
assertQuery("SELECT e FROM Employee e WHERE MOD(e.hoursWorked, 8) > 0");
247250
assertQuery("SELECT e FROM Employee e WHERE NULLIF(e.salary, 0) is null");
248251
assertQuery("SELECT e FROM Employee e WHERE SQRT(o.RESULT) > 0.0");
249252
assertQuery("SELECT e FROM Employee e WHERE SUBSTRING(e.lastName, 0, 2) = 'Bilbo'");
@@ -272,7 +275,7 @@ void functionsInOrderBy() {
272275
assertQuery("SELECT e FROM Employee e ORDER BY CURRENT_TIMESTAMP");
273276
assertQuery("SELECT e FROM Employee e ORDER BY LENGTH(e.lastName)");
274277
assertQuery("SELECT e FROM Employee e ORDER BY LOWER(e.lastName)");
275-
assertQuery("SELECT e FROM Employee e ORDER BY MOD(e.hoursWorked / 8)");
278+
assertQuery("SELECT e FROM Employee e ORDER BY MOD(e.hoursWorked, 8)");
276279
assertQuery("SELECT e FROM Employee e ORDER BY NULLIF(e.salary, 0)");
277280
assertQuery("SELECT e FROM Employee e ORDER BY SQRT(o.RESULT)");
278281
assertQuery("SELECT e FROM Employee e ORDER BY SUBSTRING(e.lastName, 0, 2)");
@@ -301,7 +304,7 @@ void functionsInGroupBy() {
301304
assertQuery("SELECT e FROM Employee e GROUP BY CURRENT_TIMESTAMP");
302305
assertQuery("SELECT e FROM Employee e GROUP BY LENGTH(e.lastName)");
303306
assertQuery("SELECT e FROM Employee e GROUP BY LOWER(e.lastName)");
304-
assertQuery("SELECT e FROM Employee e GROUP BY MOD(e.hoursWorked / 8)");
307+
assertQuery("SELECT e FROM Employee e GROUP BY MOD(e.hoursWorked, 8)");
305308
assertQuery("SELECT e FROM Employee e GROUP BY NULLIF(e.salary, 0)");
306309
assertQuery("SELECT e FROM Employee e GROUP BY SQRT(o.RESULT)");
307310
assertQuery("SELECT e FROM Employee e GROUP BY SUBSTRING(e.lastName, 0, 2)");
@@ -329,7 +332,7 @@ void functionsInHaving() {
329332
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING CURRENT_TIME > CURRENT_TIMESTAMP");
330333
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING LENGTH(e.lastName) > 0");
331334
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING LOWER(e.lastName) = 'bilbo'");
332-
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING MOD(e.hoursWorked / 8) > 0");
335+
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING MOD(e.hoursWorked, 8) > 0");
333336
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING NULLIF(e.salary, 0) is null");
334337
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING SQRT(o.RESULT) > 0.0");
335338
assertQuery("SELECT e FROM Employee e GROUP BY e.salary HAVING SUBSTRING(e.lastName, 0, 2) = 'Bilbo'");

0 commit comments

Comments
 (0)