Update JPQL grammar to support F and D suffixes.
See #3277 Original pull request: #3280
This commit is contained in:
committed by
Mark Paluch
parent
1610f6b871
commit
3998a6c70a
@@ -204,6 +204,7 @@ constructor_item
|
||||
| scalar_expression
|
||||
| aggregate_expression
|
||||
| identification_variable
|
||||
| literal
|
||||
;
|
||||
|
||||
aggregate_expression
|
||||
@@ -620,6 +621,7 @@ constructor_name
|
||||
|
||||
literal
|
||||
: STRINGLITERAL
|
||||
| JAVASTRINGLITERAL
|
||||
| INTLITERAL
|
||||
| FLOATLITERAL
|
||||
| LONGLITERAL
|
||||
@@ -852,10 +854,10 @@ WHERE : W H E R E;
|
||||
EQUAL : '=' ;
|
||||
NOT_EQUAL : '<>' | '!=' ;
|
||||
|
||||
|
||||
CHARACTER : '\'' (~ ('\'' | '\\')) '\'' ;
|
||||
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
|
||||
STRINGLITERAL : '\'' (~ ('\'' | '\\'))* '\'' ;
|
||||
FLOATLITERAL : ('0' .. '9')* '.' ('0' .. '9')+ (E '0' .. '9')* ;
|
||||
JAVASTRINGLITERAL : '"' ( ('\\' [btnfr"']) | ~('"'))* '"';
|
||||
FLOATLITERAL : ('0' .. '9')* '.' ('0' .. '9')+ (E ('0' .. '9')+)* (F|D)?;
|
||||
INTLITERAL : ('0' .. '9')+ ;
|
||||
LONGLITERAL : ('0' .. '9')+L ;
|
||||
|
||||
@@ -722,6 +722,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
tokens.addAll(visit(ctx.aggregate_expression()));
|
||||
} else if (ctx.identification_variable() != null) {
|
||||
tokens.addAll(visit(ctx.identification_variable()));
|
||||
} else if (ctx.literal() != null) {
|
||||
tokens.addAll(visit(ctx.literal()));
|
||||
}
|
||||
|
||||
return tokens;
|
||||
@@ -2152,6 +2154,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
|
||||
if (ctx.STRINGLITERAL() != null) {
|
||||
tokens.add(new JpaQueryParsingToken(ctx.STRINGLITERAL()));
|
||||
} else if (ctx.JAVASTRINGLITERAL() != null) {
|
||||
tokens.add(new JpaQueryParsingToken(ctx.JAVASTRINGLITERAL()));
|
||||
} else if (ctx.INTLITERAL() != null) {
|
||||
tokens.add(new JpaQueryParsingToken(ctx.INTLITERAL()));
|
||||
} else if (ctx.FLOATLITERAL() != null) {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*;
|
||||
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test to verify compliance of {@link JpqlParser} with standard SQL. Other than {@link JpqlSpecificationTests} tests in
|
||||
* this class check that the parser follows a lenient approach and does not error on well known concepts like numeric
|
||||
* suffix.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class JpqlComplianceTests {
|
||||
|
||||
private static String parseWithoutChanges(String query) {
|
||||
|
||||
JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(query));
|
||||
JpqlParser parser = new JpqlParser(new CommonTokenStream(lexer));
|
||||
|
||||
parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
|
||||
|
||||
JpqlParser.StartContext parsedQuery = parser.start();
|
||||
|
||||
return render(new JpqlQueryRenderer().visit(parsedQuery));
|
||||
}
|
||||
|
||||
private void assertQuery(String query) {
|
||||
|
||||
String slimmedDownQuery = reduceWhitespace(query);
|
||||
assertThat(parseWithoutChanges(slimmedDownQuery)).isEqualTo(slimmedDownQuery);
|
||||
}
|
||||
|
||||
private String reduceWhitespace(String original) {
|
||||
|
||||
return original //
|
||||
.replaceAll("[ \\t\\n]{1,}", " ") //
|
||||
.trim();
|
||||
}
|
||||
|
||||
@Test // GH-3277
|
||||
void numericLiterals() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D");
|
||||
}
|
||||
|
||||
@Test // GH-3308
|
||||
void newWithStrings() {
|
||||
assertQuery("select new com.example.demo.SampleObject(se.id, se.sampleValue, \"java\") from SampleEntity se");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -164,7 +164,12 @@ abstract class QueryEnhancerTckTests {
|
||||
|
||||
Arguments.of( //
|
||||
"select distinct m.genre from Media m where m.user = ?1 order by m.genre asc", //
|
||||
"select count(distinct m.genre) from Media m where m.user = ?1"));
|
||||
"select count(distinct m.genre) from Media m where m.user = ?1"),
|
||||
|
||||
Arguments.of( //
|
||||
"select u from User u where MOD(u.age, 10L) = 2", //
|
||||
"select count(u) from User u where MOD(u.age, 10L) = 2")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-2511, GH-2773
|
||||
|
||||
Reference in New Issue
Block a user