From 0f8279bbfa299c8ea6d469fa3e16e4b8bb717d15 Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Fri, 26 May 2023 14:35:36 -0500 Subject: [PATCH] Properly handle reserved words as entity names. In JPQL and HQL, we need to properly handle reserved words that crop up as entity names (which is legal). See #2982. --- .../data/jpa/repository/query/Hql.g4 | 1 + .../data/jpa/repository/query/Jpql.g4 | 12 ++++++------ .../jpa/repository/query/JpqlQueryRenderer.java | 8 ++------ .../repository/query/HqlQueryRendererTests.java | 17 +++++++++++++++++ .../query/JpqlQueryRendererTests.java | 17 +++++++++++++++++ 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 index 674e67721..488031b42 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 @@ -713,6 +713,7 @@ reservedWord | FETCH | FILTER | FIRST + | FLOOR | FOLLOWING | FOR | FORMAT 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 00491c841..546f49c15 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 @@ -596,12 +596,13 @@ trim_character identification_variable : IDENTIFICATION_VARIABLE - | ORDER // Gap in the spec requires supporting 'Order' as an entity name - | COUNT // Gap in the spec requires supporting 'count' as a possible name - | KEY // Gap in the sepc requires supported 'key' as a possible name - | LEFT + | f=(COUNT | INNER + | KEY + | LEFT + | ORDER | OUTER + | FLOOR) ; constructor_name @@ -682,8 +683,7 @@ collection_value_field ; entity_name - : identification_variable - | identification_variable ('.' identification_variable)* // Hibernate sometimes expands the entity name to FQDN when using named queries + : identification_variable ('.' identification_variable)* // Hibernate sometimes expands the entity name to FQDN when using named queries ; result_variable 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 0598e7029..0a148f145 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 @@ -2118,12 +2118,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor> { if (ctx.IDENTIFICATION_VARIABLE() != null) { return List.of(new JpaQueryParsingToken(ctx.IDENTIFICATION_VARIABLE())); - } else if (ctx.COUNT() != null) { - return List.of(new JpaQueryParsingToken(ctx.COUNT())); - } else if (ctx.ORDER() != null) { - return List.of(new JpaQueryParsingToken(ctx.ORDER())); - } else if (ctx.KEY() != null) { - return List.of(new JpaQueryParsingToken(ctx.KEY())); + } else if (ctx.f != null) { + return List.of(new JpaQueryParsingToken(ctx.f)); } else { return List.of(); } 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 d3a9f8326..c6c69d24e 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 @@ -1499,4 +1499,21 @@ class HqlQueryRendererTests { select sr from maxId m join SnapshotReference sr on sr.snapshot.id = m.snapshotId """); } + + @Test // GH-2982 + void floorShouldBeValidEntityName() { + + assertQuery(""" + SELECT f + FROM Floor f + WHERE f.name = :name + """); + + assertQuery(""" + SELECT r + FROM Room r + JOIN r.floor f + WHERE f.name = :name + """); + } } 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 e0124b690..14900f845 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 @@ -914,4 +914,21 @@ class JpqlQueryRendererTests { WHERE l.product.name = ?1 """); } + + @Test // GH-2982 + void floorShouldBeValidEntityName() { + + assertQuery(""" + SELECT f + FROM Floor f + WHERE f.name = :name + """); + + assertQuery(""" + SELECT r + FROM Room r + JOIN r.floor f + WHERE f.name = :name + """); + } }