diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 index 272d679c5..f321eaaf4 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 @@ -677,7 +677,8 @@ entity_type_literal escape_character : CHARACTER - | character_valued_input_parameter // + | string_literal + | character_valued_input_parameter ; numeric_literal diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 index a1c69583f..c44f3495f 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 @@ -653,7 +653,8 @@ entity_type_literal escape_character : CHARACTER - | character_valued_input_parameter // + | string_literal + | character_valued_input_parameter ; numeric_literal @@ -949,7 +950,7 @@ NOT_EQUAL : '<>' | '!=' ; CHARACTER : '\'' (~ ('\'' | '\\')) '\'' ; IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ; -STRINGLITERAL : '\'' (~ ('\'' | '\\'))* '\'' ; +STRINGLITERAL : '\'' (~ ('\'' | '\\')|'\\')* '\'' ; JAVASTRINGLITERAL : '"' ( ('\\' [btnfr"']) | ~('"'))* '"'; FLOATLITERAL : ('0' .. '9')* '.' ('0' .. '9')+ (E ('0' .. '9')+)* (F|D)?; INTLITERAL : ('0' .. '9')+ ; diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java index 5bd453a81..836b0b372 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java @@ -2418,7 +2418,16 @@ class EqlQueryRenderer extends EqlBaseVisitor> { @Override public List visitEscape_character(EqlParser.Escape_characterContext ctx) { - return List.of(new JpaQueryParsingToken(ctx.CHARACTER())); + + if (ctx.CHARACTER() != null) { + return List.of(new JpaQueryParsingToken(ctx.CHARACTER())); + } else if (ctx.character_valued_input_parameter() != null) { + return visit(ctx.character_valued_input_parameter()); + } else if (ctx.string_literal() != null) { + return visit(ctx.string_literal()); + } + + return List.of(); } @Override diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java index 58f549ace..74ec8a790 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java @@ -2225,7 +2225,16 @@ class JpqlQueryRenderer extends JpqlBaseVisitor> { @Override public List visitEscape_character(JpqlParser.Escape_characterContext ctx) { - return List.of(new JpaQueryParsingToken(ctx.CHARACTER())); + + if (ctx.CHARACTER() != null) { + return List.of(new JpaQueryParsingToken(ctx.CHARACTER())); + } else if (ctx.character_valued_input_parameter() != null) { + return visit(ctx.character_valued_input_parameter()); + } else if (ctx.string_literal() != null) { + return visit(ctx.string_literal()); + } + + return List.of(); } @Override diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java index 148362525..f744f1756 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java @@ -1038,6 +1038,14 @@ class EqlQueryRendererTests { assertQuery(query); } + @Test // GH-3873 + void escapeClauseShouldWork() { + assertQuery("select t.name from SomeDbo t where t.name LIKE :name escape '\\\\'"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE '\\\\'"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE ?1"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE :param"); + } + @ParameterizedTest // GH-3451 @MethodSource("reservedWords") void entityNameWithPackageContainingReservedWord(String reservedWord) { 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 47568fc19..dd24a883e 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 @@ -1569,6 +1569,9 @@ class HqlQueryRendererTests { @Test // GH-3040 void escapeClauseShouldWork() { assertQuery("select t.name from SomeDbo t where t.name LIKE :name escape '\\\\'"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE '\\\\'"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE ?1"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE :param"); } @Test // GH-3062, GH-3056 diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java index 12d254eed..bbec33501 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java @@ -1046,6 +1046,14 @@ class JpqlQueryRendererTests { assertQuery(query); } + @Test // GH-3873 + void escapeClauseShouldWork() { + assertQuery("select t.name from SomeDbo t where t.name LIKE :name escape '\\\\'"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE '\\\\'"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE ?1"); + assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE :param"); + } + @ParameterizedTest // GH-3451 @MethodSource("reservedWords") void entityNameWithPackageContainingReservedWord(String reservedWord) {