/* * 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 : ('#')('{')(.)*?('}') ;