Skip to content

Commit

Permalink
Fix parsing entity names in JPQL query with package names that contai…
Browse files Browse the repository at this point in the history
…n reserved words.

Resolves: #3451
Original pull request: #3457
  • Loading branch information
christophstrobl authored and mp911de committed Apr 30, 2024
1 parent f9c4984 commit 2688097
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ identification_variable
;

constructor_name
: state_field_path_expression
: entity_name
;

literal
Expand Down Expand Up @@ -696,7 +696,7 @@ collection_value_field
;

entity_name
: identification_variable ('.' identification_variable)* // Hibernate sometimes expands the entity name to FQDN when using named queries
: reserved_word ('.' reserved_word)* // Hibernate sometimes expands the entity name to FQDN when using named queries
;

result_variable
Expand Down Expand Up @@ -724,6 +724,90 @@ character_valued_input_parameter
| input_parameter
;

reserved_word
: IDENTIFICATION_VARIABLE
| f=(ABS
|ALL
|AND
|ANY
|AS
|ASC
|AVG
|BETWEEN
|BOTH
|BY
|CASE
|CEILING
|COALESCE
|CONCAT
|COUNT
|CURRENT_DATE
|CURRENT_TIME
|CURRENT_TIMESTAMP
|DATE
|DATETIME
|DELETE
|DESC
|DISTINCT
|END
|ELSE
|EMPTY
|ENTRY
|ESCAPE
|EXISTS
|EXP
|EXTRACT
|FALSE
|FETCH
|FLOOR
|FUNCTION
|IN
|INDEX
|INNER
|IS
|KEY
|LEFT
|LENGTH
|LIKE
|LN
|LOCAL
|LOCATE
|LOWER
|MAX
|MEMBER
|MIN
|MOD
|NEW
|NOT
|NULL
|NULLIF
|OBJECT
|OF
|ON
|OR
|ORDER
|OUTER
|POWER
|ROUND
|SELECT
|SET
|SIGN
|SIZE
|SOME
|SQRT
|SUBSTRING
|SUM
|THEN
|TIME
|TRAILING
|TREAT
|TRIM
|TRUE
|TYPE
|UPDATE
|UPPER
|VALUE)
;
/*
Lexer rules
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.util.ArrayList;
import java.util.List;

import org.springframework.data.jpa.repository.query.JpqlParser.Reserved_wordContext;

/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders a JPQL query without making any changes.
*
Expand Down Expand Up @@ -2143,7 +2145,7 @@ public List<JpaQueryParsingToken> visitConstructor_name(JpqlParser.Constructor_n

List<JpaQueryParsingToken> tokens = new ArrayList<>();

tokens.addAll(visit(ctx.state_field_path_expression()));
tokens.addAll(visit(ctx.entity_name()));
NOSPACE(tokens);

return tokens;
Expand Down Expand Up @@ -2296,8 +2298,8 @@ public List<JpaQueryParsingToken> visitEntity_name(JpqlParser.Entity_nameContext

List<JpaQueryParsingToken> tokens = new ArrayList<>();

ctx.identification_variable().forEach(identificationVariableContext -> {
tokens.addAll(visit(identificationVariableContext));
ctx.reserved_word().forEach(ctx2 -> {
tokens.addAll(visitReserved_word(ctx2));
NOSPACE(tokens);
tokens.add(TOKEN_DOT);
});
Expand Down Expand Up @@ -2347,4 +2349,15 @@ public List<JpaQueryParsingToken> visitCharacter_valued_input_parameter(
return List.of();
}
}

@Override
public List<JpaQueryParsingToken> visitReserved_word(Reserved_wordContext ctx) {
if (ctx.IDENTIFICATION_VARIABLE() != null) {
return List.of(new JpaQueryParsingToken(ctx.IDENTIFICATION_VARIABLE()));
} else if (ctx.f != null) {
return List.of(new JpaQueryParsingToken(ctx.f));
} else {
return List.of();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*;

import java.util.stream.Stream;

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;

/**
Expand Down Expand Up @@ -56,6 +60,10 @@ private static String parseWithoutChanges(String query) {
return render(new JpqlQueryRenderer().visit(parsedQuery));
}

public static Stream<Arguments> reservedWords() {
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
}

private void assertQuery(String query) {

String slimmedDownQuery = reduceWhitespace(query);
Expand Down Expand Up @@ -1019,4 +1027,14 @@ void signedLiteralShouldWork(String query) {
void signedExpressionsShouldWork(String query) {
assertQuery(query);
}

@ParameterizedTest // GH-3451
@MethodSource({"reservedWords"})
void entityNameWithPackageContainingReservedWord(String reservedWord) {

String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
assertQuery(source);
}


}

0 comments on commit 2688097

Please sign in to comment.