Files

870 lines
21 KiB
ANTLR

/*
* Copyright 2011-2023 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.
*/
grammar Jpql;
@header {
/**
* JPQL per https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1.html#bnf
*
* This is JPA BNF for JPQL. There are gaps and inconsistencies in the BNF itself, explained by other fragments of the spec.
*
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#bnf
* @author Greg Turnquist
* @author Christoph Strobl
* @since 3.1
*/
}
/*
Parser rules
*/
start
: ql_statement EOF
;
ql_statement
: select_statement
| update_statement
| delete_statement
;
select_statement
: select_clause from_clause (where_clause)? (groupby_clause)? (having_clause)? (orderby_clause)?
;
update_statement
: update_clause (where_clause)?
;
delete_statement
: delete_clause (where_clause)?
;
from_clause
: FROM identification_variable_declaration (',' identificationVariableDeclarationOrCollectionMemberDeclaration )*
;
// This parser rule is needed to iterate over these two types from #from_clause
identificationVariableDeclarationOrCollectionMemberDeclaration
: identification_variable_declaration
| collection_member_declaration
;
identification_variable_declaration
: range_variable_declaration (join | fetch_join)*
;
range_variable_declaration
: entity_name AS? identification_variable
;
join
: join_spec join_association_path_expression AS? identification_variable (join_condition)?
;
fetch_join
: join_spec FETCH join_association_path_expression
;
join_spec
: ((LEFT (OUTER)?) | INNER)? JOIN
;
join_condition
: ON conditional_expression
;
join_association_path_expression
: join_collection_valued_path_expression
| join_single_valued_path_expression
| TREAT '(' join_collection_valued_path_expression AS subtype ')'
| TREAT '(' join_single_valued_path_expression AS subtype ')'
;
join_collection_valued_path_expression
: identification_variable '.' (single_valued_embeddable_object_field '.')* collection_valued_field
;
join_single_valued_path_expression
: identification_variable '.' (single_valued_embeddable_object_field '.')* single_valued_object_field
;
collection_member_declaration
: IN '(' collection_valued_path_expression ')' AS? identification_variable
;
qualified_identification_variable
: map_field_identification_variable
| ENTRY '(' identification_variable ')'
;
map_field_identification_variable
: KEY '(' identification_variable ')'
| VALUE '(' identification_variable ')'
;
single_valued_path_expression
: qualified_identification_variable
| TREAT '(' qualified_identification_variable AS subtype ')'
| state_field_path_expression
| single_valued_object_path_expression
;
general_identification_variable
: identification_variable
| map_field_identification_variable
;
general_subpath
: simple_subpath
| treated_subpath ('.' single_valued_object_field)*
;
simple_subpath
: general_identification_variable
| general_identification_variable ('.' single_valued_object_field)*
;
treated_subpath
: TREAT '(' general_subpath AS subtype ')'
;
state_field_path_expression
: general_subpath '.' state_field
;
state_valued_path_expression
: state_field_path_expression
| general_identification_variable
;
single_valued_object_path_expression
: general_subpath '.' single_valued_object_field
;
collection_valued_path_expression
: general_subpath '.' collection_value_field // BNF at end of spec has a typo
;
update_clause
: UPDATE entity_name (AS? identification_variable)? SET update_item (',' update_item)*
;
update_item
: (identification_variable '.')? (single_valued_embeddable_object_field '.')* (state_field | single_valued_object_field) EQUAL new_value
;
new_value
: scalar_expression
| simple_entity_expression
| NULL
;
delete_clause
: DELETE FROM entity_name (AS? identification_variable)?
;
select_clause
: SELECT (DISTINCT)? select_item (',' select_item)*
;
select_item
: select_expression (AS? result_variable)?
;
select_expression
: single_valued_path_expression
| scalar_expression
| aggregate_expression
| identification_variable
| OBJECT '(' identification_variable ')'
| constructor_expression
;
constructor_expression
: NEW constructor_name '(' constructor_item (',' constructor_item)* ')'
;
constructor_item
: single_valued_path_expression
| scalar_expression
| aggregate_expression
| identification_variable
| literal
;
aggregate_expression
: (AVG | MAX | MIN | SUM) '(' (DISTINCT)? state_valued_path_expression ')'
| COUNT '(' (DISTINCT)? (identification_variable | state_valued_path_expression | single_valued_object_path_expression) ')'
| function_invocation
;
where_clause
: WHERE conditional_expression
;
groupby_clause
: GROUP BY groupby_item (',' groupby_item)*
;
groupby_item
: single_valued_path_expression
| identification_variable
;
having_clause
: HAVING conditional_expression
;
orderby_clause
: ORDER BY orderby_item (',' orderby_item)*
;
// TODO Error in spec BNF, correctly shown elsewhere in spec.
orderby_item
: (state_field_path_expression | general_identification_variable | result_variable ) (ASC | DESC)?
;
subquery
: simple_select_clause subquery_from_clause (where_clause)? (groupby_clause)? (having_clause)?
;
subquery_from_clause
: FROM subselect_identification_variable_declaration (',' (subselect_identification_variable_declaration | collection_member_declaration))*
;
subselect_identification_variable_declaration
: identification_variable_declaration
| derived_path_expression AS? identification_variable (join)*
| derived_collection_member_declaration
;
derived_path_expression
: general_derived_path '.' single_valued_object_field
| general_derived_path '.' collection_valued_field
;
general_derived_path
: simple_derived_path
| treated_derived_path ('.' single_valued_object_field)*
;
simple_derived_path
: superquery_identification_variable ('.' single_valued_object_field)*
;
treated_derived_path
: TREAT '(' general_derived_path AS subtype ')'
;
derived_collection_member_declaration
: IN superquery_identification_variable '.' (single_valued_object_field '.')* collection_valued_field
;
simple_select_clause
: SELECT (DISTINCT)? simple_select_expression
;
simple_select_expression
: single_valued_path_expression
| scalar_expression
| aggregate_expression
| identification_variable
;
scalar_expression
: arithmetic_expression
| string_expression
| enum_expression
| datetime_expression
| boolean_expression
| case_expression
| entity_type_expression
;
conditional_expression
: conditional_term
| conditional_expression OR conditional_term
;
conditional_term
: conditional_factor
| conditional_term AND conditional_factor
;
conditional_factor
: (NOT)? conditional_primary
;
conditional_primary
: simple_cond_expression
| '(' conditional_expression ')'
;
simple_cond_expression
: comparison_expression
| between_expression
| in_expression
| like_expression
| null_comparison_expression
| empty_collection_comparison_expression
| collection_member_expression
| exists_expression
;
between_expression
: arithmetic_expression (NOT)? BETWEEN arithmetic_expression AND arithmetic_expression
| string_expression (NOT)? BETWEEN string_expression AND string_expression
| datetime_expression (NOT)? BETWEEN datetime_expression AND datetime_expression
;
in_expression
: (state_valued_path_expression | type_discriminator) (NOT)? IN (('(' in_item (',' in_item)* ')') | ( '(' subquery ')') | collection_valued_input_parameter)
;
in_item
: literal
| single_valued_input_parameter
;
like_expression
: string_expression (NOT)? LIKE ('%')? pattern_value ('%')? (ESCAPE escape_character)?
;
null_comparison_expression
: (single_valued_path_expression | input_parameter) IS (NOT)? NULL
;
empty_collection_comparison_expression
: collection_valued_path_expression IS (NOT)? EMPTY
;
collection_member_expression
: entity_or_value_expression (NOT)? MEMBER (OF)? collection_valued_path_expression
;
entity_or_value_expression
: single_valued_object_path_expression
| state_field_path_expression
| simple_entity_or_value_expression
;
simple_entity_or_value_expression
: identification_variable
| input_parameter
| literal
;
exists_expression
: (NOT)? EXISTS '(' subquery ')'
;
all_or_any_expression
: (ALL | ANY | SOME) '(' subquery ')'
;
comparison_expression
: string_expression comparison_operator (string_expression | all_or_any_expression)
| boolean_expression op=(EQUAL | NOT_EQUAL) (boolean_expression | all_or_any_expression)
| enum_expression op=(EQUAL | NOT_EQUAL) (enum_expression | all_or_any_expression)
| datetime_expression comparison_operator (datetime_expression | all_or_any_expression)
| entity_expression op=(EQUAL | NOT_EQUAL) (entity_expression | all_or_any_expression)
| arithmetic_expression comparison_operator (arithmetic_expression | all_or_any_expression)
| entity_type_expression op=(EQUAL | NOT_EQUAL) entity_type_expression
;
comparison_operator
: op=EQUAL
| op='>'
| op='>='
| op='<'
| op='<='
| op=NOT_EQUAL
;
arithmetic_expression
: arithmetic_term
| arithmetic_expression op=('+' | '-') arithmetic_term
;
arithmetic_term
: arithmetic_factor
| arithmetic_term op=('*' | '/') arithmetic_factor
;
arithmetic_factor
: op=('+' | '-')? arithmetic_primary
;
arithmetic_primary
: state_valued_path_expression
| numeric_literal
| '(' arithmetic_expression ')'
| input_parameter
| functions_returning_numerics
| aggregate_expression
| case_expression
| function_invocation
| '(' subquery ')'
;
string_expression
: state_valued_path_expression
| string_literal
| input_parameter
| functions_returning_strings
| aggregate_expression
| case_expression
| function_invocation
| '(' subquery ')'
;
datetime_expression
: state_valued_path_expression
| input_parameter
| functions_returning_datetime
| aggregate_expression
| case_expression
| function_invocation
| date_time_timestamp_literal
| '(' subquery ')'
;
boolean_expression
: state_valued_path_expression
| boolean_literal
| input_parameter
| case_expression
| function_invocation
| '(' subquery ')'
;
enum_expression
: state_valued_path_expression
| enum_literal
| input_parameter
| case_expression
| '(' subquery ')'
;
entity_expression
: single_valued_object_path_expression
| simple_entity_expression
;
simple_entity_expression
: identification_variable
| input_parameter
;
entity_type_expression
: type_discriminator
| entity_type_literal
| input_parameter
;
type_discriminator
: TYPE '(' (general_identification_variable | single_valued_object_path_expression | input_parameter) ')'
;
functions_returning_numerics
: LENGTH '(' string_expression ')'
| LOCATE '(' string_expression ',' string_expression (',' arithmetic_expression)? ')'
| ABS '(' arithmetic_expression ')'
| CEILING '(' arithmetic_expression ')'
| EXP '(' arithmetic_expression ')'
| FLOOR '(' arithmetic_expression ')'
| LN '(' arithmetic_expression ')'
| SIGN '(' arithmetic_expression ')'
| SQRT '(' arithmetic_expression ')'
| MOD '(' arithmetic_expression ',' arithmetic_expression ')'
| POWER '(' arithmetic_expression ',' arithmetic_expression ')'
| ROUND '(' arithmetic_expression ',' arithmetic_expression ')'
| SIZE '(' collection_valued_path_expression ')'
| INDEX '(' identification_variable ')'
| extract_datetime_field
;
functions_returning_datetime
: CURRENT_DATE
| CURRENT_TIME
| CURRENT_TIMESTAMP
| LOCAL DATE
| LOCAL TIME
| LOCAL DATETIME
| extract_datetime_part
;
functions_returning_strings
: CONCAT '(' string_expression ',' string_expression (',' string_expression)* ')'
| SUBSTRING '(' string_expression ',' arithmetic_expression (',' arithmetic_expression)? ')'
| TRIM '(' ((trim_specification)? (trim_character)? FROM)? string_expression ')'
| LOWER '(' string_expression ')'
| UPPER '(' string_expression ')'
;
trim_specification
: LEADING
| TRAILING
| BOTH
;
function_invocation
: FUNCTION '(' function_name (',' function_arg)* ')'
;
extract_datetime_field
: EXTRACT '(' datetime_field FROM datetime_expression ')'
;
datetime_field
: identification_variable
;
extract_datetime_part
: EXTRACT '(' datetime_part FROM datetime_expression ')'
;
datetime_part
: identification_variable
;
function_arg
: literal
| state_valued_path_expression
| input_parameter
| scalar_expression
;
case_expression
: general_case_expression
| simple_case_expression
| coalesce_expression
| nullif_expression
;
general_case_expression
: CASE when_clause (when_clause)* ELSE scalar_expression END
;
when_clause
: WHEN conditional_expression THEN scalar_expression
;
simple_case_expression
: CASE case_operand simple_when_clause (simple_when_clause)* ELSE scalar_expression END
;
case_operand
: state_valued_path_expression
| type_discriminator
;
simple_when_clause
: WHEN scalar_expression THEN scalar_expression
;
coalesce_expression
: COALESCE '(' scalar_expression (',' scalar_expression)+ ')'
;
nullif_expression
: NULLIF '(' scalar_expression ',' scalar_expression ')'
;
/*******************
Gaps in the spec.
*******************/
trim_character
: CHARACTER
| character_valued_input_parameter
;
identification_variable
: IDENTIFICATION_VARIABLE
| f=(AVG
| COUNT
| DATE
| FROM
| INNER
| KEY
| LEFT
| MAX
| MIN
| NEW
| ORDER
| OUTER
| POWER
| FLOOR
| SIGN
| SUM
| TIME
| TYPE
| VALUE)
;
constructor_name
: state_field_path_expression
;
literal
: STRINGLITERAL
| JAVASTRINGLITERAL
| INTLITERAL
| FLOATLITERAL
| LONGLITERAL
| boolean_literal
| entity_type_literal
;
input_parameter
: ':' SPEL
| '?' SPEL
| '?' INTLITERAL
| ':' identification_variable
;
pattern_value
: string_expression
;
date_time_timestamp_literal
: STRINGLITERAL
;
entity_type_literal
: identification_variable
;
escape_character
: CHARACTER
| character_valued_input_parameter //
;
numeric_literal
: INTLITERAL
| FLOATLITERAL
| LONGLITERAL
;
boolean_literal
: TRUE
| FALSE
;
enum_literal
: state_field_path_expression
;
string_literal
: CHARACTER
| STRINGLITERAL
;
single_valued_embeddable_object_field
: identification_variable
;
subtype
: identification_variable
;
collection_valued_field
: identification_variable
;
single_valued_object_field
: identification_variable
;
state_field
: identification_variable
;
collection_value_field
: identification_variable
;
entity_name
: identification_variable ('.' identification_variable)* // Hibernate sometimes expands the entity name to FQDN when using named queries
;
result_variable
: identification_variable
;
superquery_identification_variable
: identification_variable
;
collection_valued_input_parameter
: input_parameter
;
single_valued_input_parameter
: input_parameter
;
function_name
: string_literal
;
character_valued_input_parameter
: CHARACTER
| input_parameter
;
/*
Lexer rules
*/
WS : [ \t\r\n] -> skip ;
// Build up case-insentive tokens
fragment A: 'a' | 'A';
fragment B: 'b' | 'B';
fragment C: 'c' | 'C';
fragment D: 'd' | 'D';
fragment E: 'e' | 'E';
fragment F: 'f' | 'F';
fragment G: 'g' | 'G';
fragment H: 'h' | 'H';
fragment I: 'i' | 'I';
fragment J: 'j' | 'J';
fragment K: 'k' | 'K';
fragment L: 'l' | 'L';
fragment M: 'm' | 'M';
fragment N: 'n' | 'N';
fragment O: 'o' | 'O';
fragment P: 'p' | 'P';
fragment Q: 'q' | 'Q';
fragment R: 'r' | 'R';
fragment S: 's' | 'S';
fragment T: 't' | 'T';
fragment U: 'u' | 'U';
fragment V: 'v' | 'V';
fragment W: 'w' | 'W';
fragment X: 'x' | 'X';
fragment Y: 'y' | 'Y';
fragment Z: 'z' | 'Z';
// The following are reserved identifiers:
ABS : A B S;
ALL : A L L;
AND : A N D;
ANY : A N Y;
AS : A S;
ASC : A S C;
AVG : A V G;
BETWEEN : B E T W E E N;
BOTH : B O T H;
BY : B Y;
CASE : C A S E;
CEILING : C E I L I N G;
COALESCE : C O A L E S C E;
CONCAT : C O N C A T;
COUNT : C O U N T;
CURRENT_DATE : C U R R E N T '_' D A T E;
CURRENT_TIME : C U R R E N T '_' T I M E;
CURRENT_TIMESTAMP : C U R R E N T '_' T I M E S T A M P;
DATE : D A T E;
DATETIME : D A T E T I M E ;
DELETE : D E L E T E;
DESC : D E S C;
DISTINCT : D I S T I N C T;
END : E N D;
ELSE : E L S E;
EMPTY : E M P T Y;
ENTRY : E N T R Y;
ESCAPE : E S C A P E;
EXISTS : E X I S T S;
EXP : E X P;
EXTRACT : E X T R A C T;
FALSE : F A L S E;
FETCH : F E T C H;
FLOOR : F L O O R;
FROM : F R O M;
FUNCTION : F U N C T I O N;
GROUP : G R O U P;
HAVING : H A V I N G;
IN : I N;
INDEX : I N D E X;
INNER : I N N E R;
IS : I S;
JOIN : J O I N;
KEY : K E Y;
LEADING : L E A D I N G;
LEFT : L E F T;
LENGTH : L E N G T H;
LIKE : L I K E;
LN : L N;
LOCAL : L O C A L;
LOCATE : L O C A T E;
LOWER : L O W E R;
MAX : M A X;
MEMBER : M E M B E R;
MIN : M I N;
MOD : M O D;
NEW : N E W;
NOT : N O T;
NULL : N U L L;
NULLIF : N U L L I F;
OBJECT : O B J E C T;
OF : O F;
ON : O N;
OR : O R;
ORDER : O R D E R;
OUTER : O U T E R;
POWER : P O W E R;
ROUND : R O U N D;
SELECT : S E L E C T;
SET : S E T;
SIGN : S I G N;
SIZE : S I Z E;
SOME : S O M E;
SQRT : S Q R T;
SUBSTRING : S U B S T R I N G;
SUM : S U M;
THEN : T H E N;
TIME : T I M E;
TRAILING : T R A I L I N G;
TREAT : T R E A T;
TRIM : T R I M;
TRUE : T R U E;
TYPE : T Y P E;
UPDATE : U P D A T E;
UPPER : U P P E R;
VALUE : V A L U E;
WHEN : W H E N;
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 : '\'' (~ ('\'' | '\\'))* '\'' ;
JAVASTRINGLITERAL : '"' ( ('\\' [btnfr"']) | ~('"'))* '"';
FLOATLITERAL : ('0' .. '9')* '.' ('0' .. '9')+ (E ('0' .. '9')+)* (F|D)?;
INTLITERAL : ('0' .. '9')+ ;
LONGLITERAL : ('0' .. '9')+L ;
SPEL : ('#')('{')(.)*?('}') ;