| /* |
| * Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation |
| // |
| package org.eclipse.persistence.jpa.jpql.parser; |
| |
| import org.eclipse.persistence.jpa.jpql.EclipseLinkVersion; |
| import org.eclipse.persistence.jpa.jpql.JPAVersion; |
| import org.eclipse.persistence.jpa.jpql.parser.FunctionExpressionFactory.ParameterCount; |
| import static org.eclipse.persistence.jpa.jpql.parser.Expression.*; |
| |
| /** |
| * <p>This {@link JPQLGrammar} provides support for parsing JPQL queries defined in <a |
| * href="http://jcp.org/en/jsr/detail?id=317">JSR-338 - Java Persistence 2.1</a> and the additional |
| * support provided by EclipseLink 2.4.</p> |
| * |
| * The BNFs of the additional support are the following: |
| * |
| * <pre><code> select_statement ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause] {union_clause}* |
| * |
| * union_clause ::= { UNION | INTERSECT | EXCEPT} [ALL] subquery |
| * |
| * from_clause ::= FROM identification_variable_declaration {, {identification_variable_declaration | |
| * collection_member_declaration | |
| * (subquery) | |
| * table_variable_declaration }}* |
| * |
| * range_variable_declaration ::= root_object [AS] identification_variable |
| * |
| * root_object ::= abstract_schema_name | fully_qualified_class_name |
| * |
| * table_variable_declaration ::= table_expression [AS] identification_variable |
| * |
| * join ::= join_spec { abstract_schema_name | join_association_path_expression } [AS] identification_variable [join_condition] |
| * |
| * functions_returning_datetime ::= cast_expression | |
| * extract_expression | |
| * ... |
| * |
| * functions_returning_string ::= cast_expression | |
| * extract_expression | |
| * ... |
| * |
| * functions_returning_numeric ::= cast_expression | |
| * extract_expression | |
| * ... |
| * |
| * simple_cond_expression ::= regexp_expression | |
| * ... |
| * |
| * function_expression ::= { FUNC | FUNCTION | OPERATOR | SQL | COLUMN } (string_literal {, function_arg}*) |
| * |
| * regexp_expression ::= string_expression REGEXP pattern_value |
| * |
| * extract_expression ::= EXTRACT(date_part_literal [FROM] scalar_expression) |
| * |
| * table_expression ::= TABLE(string_literal) |
| * |
| * date_part_literal ::= { MICROSECOND | SECOND | MINUTE | HOUR | DAY | WEEK | MONTH | QUARTER | |
| * YEAR | SECOND_MICROSECOND | MINUTE_MICROSECOND | MINUTE_SECOND | |
| * HOUR_MICROSECOND | HOUR_SECOND | HOUR_MINUTE | DAY_MICROSECOND | |
| * DAY_SECOND | DAY_MINUTE | DAY_HOUR | YEAR_MONTH, etc } |
| * |
| * cast_expression ::= CAST(scalar_expression [AS] database_type) |
| * |
| * database_type ::= data_type_literal [( [numeric_literal [, numeric_literal]] )] |
| * |
| * data_type_literal ::= [CHAR, VARCHAR, NUMERIC, INTEGER, DATE, TIME, TIMESTAMP, etc]</code></pre> |
| * |
| * <p>Provisional API: This interface is part of an interim API that is still under development and |
| * expected to change significantly before reaching stability. It is available at this early stage |
| * to solicit feedback from pioneering adopters on the understanding that any code that uses this |
| * API will almost certainly be broken (repeatedly) as the API evolves.</p> |
| * |
| * @version 2.5 |
| * @since 2.4 |
| * @author Pascal Filion |
| */ |
| @SuppressWarnings("nls") |
| public final class EclipseLinkJPQLGrammar2_4 extends AbstractJPQLGrammar { |
| |
| /** |
| * The singleton instance of this {@link EclipseLinkJPQLGrammar2_4}. |
| */ |
| private static final JPQLGrammar INSTANCE = new EclipseLinkJPQLGrammar2_4(); |
| |
| /** |
| * The EclipseLink version, which is 2.4. |
| */ |
| public static final EclipseLinkVersion VERSION = EclipseLinkVersion.VERSION_2_4; |
| |
| /** |
| * Creates a new <code>EclipseLinkJPQLGrammar2_4</code>. |
| */ |
| public EclipseLinkJPQLGrammar2_4() { |
| super(); |
| } |
| |
| /** |
| * Creates a new <code>EclipseLinkJPQLGrammar2_4</code>. |
| * |
| * @param jpqlGrammar The {@link JPQLGrammar} to extend with the content of this one without |
| * instantiating the base {@link JPQLGrammar} |
| */ |
| private EclipseLinkJPQLGrammar2_4(AbstractJPQLGrammar jpqlGrammar) { |
| super(jpqlGrammar); |
| } |
| |
| /** |
| * Extends the given {@link JPQLGrammar} with the information of this one without instantiating |
| * the base {@link JPQLGrammar}. |
| * |
| * @param jpqlGrammar The {@link JPQLGrammar} to extend with the content of this one without |
| * instantiating the base {@link JPQLGrammar} |
| */ |
| public static void extend(AbstractJPQLGrammar jpqlGrammar) { |
| new EclipseLinkJPQLGrammar2_4(jpqlGrammar); |
| } |
| |
| /** |
| * Returns the singleton instance of this class. |
| * |
| * @return The singleton instance of {@link EclipseLinkJPQLGrammar2_4} |
| */ |
| public static JPQLGrammar instance() { |
| return INSTANCE; |
| } |
| |
| @Override |
| protected JPQLGrammar buildBaseGrammar() { |
| |
| // First build the JPQL 2.1 grammar |
| JPQLGrammar2_1 jpqlGrammar = new JPQLGrammar2_1(); |
| |
| // Extend it by adding the EclipseLink 2.0 additional support |
| EclipseLinkJPQLGrammar2_0.extend(jpqlGrammar); |
| |
| // Extend it by adding the EclipseLink 2.1 additional support |
| EclipseLinkJPQLGrammar2_1.extend(jpqlGrammar); |
| |
| return jpqlGrammar; |
| } |
| |
| @Override |
| public JPAVersion getJPAVersion() { |
| return JPAVersion.VERSION_2_1; |
| } |
| |
| @Override |
| public String getProvider() { |
| return DefaultEclipseLinkJPQLGrammar.PROVIDER_NAME; |
| } |
| |
| @Override |
| public String getProviderVersion() { |
| return VERSION.getVersion(); |
| } |
| |
| @Override |
| protected void initializeBNFs() { |
| |
| registerBNF(new CastExpressionBNF()); |
| registerBNF(new DatabaseTypeQueryBNF()); |
| registerBNF(new ExtractExpressionBNF()); |
| registerBNF(new InternalColumnExpressionBNF()); |
| registerBNF(new RegexpExpressionBNF()); |
| registerBNF(new TableExpressionBNF()); |
| registerBNF(new TableVariableDeclarationBNF()); |
| registerBNF(new UnionClauseBNF()); |
| |
| // This is required to properly validate an entity name used as a join association path |
| addChildBNF(JoinAssociationPathExpressionBNF.ID, AbstractSchemaNameBNF.ID); |
| |
| // Override (internal) simple_select_expression to add support for result variable |
| registerBNF(new SimpleResultVariableBNF()); |
| |
| // Note: This should only support SQL expression |
| addChildBNF(SimpleConditionalExpressionBNF.ID, FunctionExpressionBNF.ID); |
| |
| // CAST |
| addChildBNF(FunctionsReturningDatetimeBNF.ID, CastExpressionBNF.ID); |
| addChildBNF(FunctionsReturningNumericsBNF.ID, CastExpressionBNF.ID); |
| addChildBNF(FunctionsReturningStringsBNF.ID, CastExpressionBNF.ID); |
| |
| // EXTRACT |
| addChildBNF(FunctionsReturningDatetimeBNF.ID, ExtractExpressionBNF.ID); |
| addChildBNF(FunctionsReturningNumericsBNF.ID, ExtractExpressionBNF.ID); |
| addChildBNF(FunctionsReturningStringsBNF.ID, ExtractExpressionBNF.ID); |
| |
| // REGEXP |
| addChildBNF(SimpleConditionalExpressionBNF.ID, RegexpExpressionBNF.ID); |
| |
| // Add subquery support to RangeDeclarationBNF |
| addChildBNF(RangeDeclarationBNF.ID, SubqueryBNF.ID); |
| |
| // Add table declaration to the FROM clause's declaration |
| addChildBNF(InternalFromClauseBNF.ID, TableVariableDeclarationBNF.ID); |
| addChildBNF(InternalSimpleFromClauseBNF.ID, TableVariableDeclarationBNF.ID); |
| |
| // Trickle down the handling of a sub expression (subquery) to RangeVariableDeclaration |
| // and in order to keep the hierarchy intact, otherwise the default behavior would be |
| // FromClause would parse the subquery immediately. |
| // |
| // FromClause |
| // |- IdentificationVariableDeclaration |
| // |- RangeVariableDeclaration [(subquery) AS identification_variable] |
| // |- SubExpression |
| // |- SimpleSelectStatement |
| setHandleSubExpression(InternalFromClauseBNF.ID, true); |
| setHandleSubExpression(InternalSimpleFromClauseBNF.ID, true); |
| setHandleSubExpression(IdentificationVariableDeclarationBNF.ID, true); |
| setHandleSubExpression(RangeVariableDeclarationBNF.ID, true); |
| } |
| |
| @Override |
| protected void initializeExpressionFactories() { |
| |
| registerFactory(new CastExpressionFactory()); |
| registerFactory(new DatabaseTypeFactory()); |
| registerFactory(new ExtractExpressionFactory()); |
| registerFactory(new JoinCollectionValuedPathExpressionFactory()); |
| registerFactory(new OnClauseFactory()); |
| registerFactory(new RegexpExpressionFactory()); |
| registerFactory(new TableExpressionFactory()); |
| registerFactory(new TableVariableDeclarationFactory()); |
| registerFactory(new UnionClauseFactory()); |
| |
| // Add a new FunctionExpression for 'COLUMN' since it has different rules |
| FunctionExpressionFactory columnExpressionFactory = new FunctionExpressionFactory(COLUMN, COLUMN); |
| columnExpressionFactory.setParameterCount(ParameterCount.ONE); |
| columnExpressionFactory.setParameterQueryBNFId(InternalColumnExpressionBNF.ID); |
| registerFactory(columnExpressionFactory); |
| |
| // Add COLUMN ExpressionFactory to FunctionExpressionBNF |
| addChildFactory(FunctionExpressionBNF.ID, COLUMN); |
| |
| // Change the fallback ExpressionFactory to add support for an abstract schema name |
| // as a valid join association path expression |
| setFallbackExpressionFactoryId(JoinAssociationPathExpressionBNF.ID, JoinCollectionValuedPathExpressionFactory.ID); |
| } |
| |
| @Override |
| protected void initializeIdentifiers() { |
| |
| // Expand FunctionExpression to support 'FUNCTION', 'OPERATOR' and 'SQL' |
| addIdentifiers(FunctionExpressionFactory.ID, FUNCTION, OPERATOR, SQL); |
| |
| registerIdentifierRole(CAST, IdentifierRole.FUNCTION); // FUNCTION(n, x1, ..., x2) |
| registerIdentifierRole(COLUMN, IdentifierRole.FUNCTION); // FUNCTION(n, x1, ..., x2) |
| registerIdentifierRole(EXCEPT, IdentifierRole.CLAUSE); |
| registerIdentifierRole(EXTRACT, IdentifierRole.FUNCTION); // EXTRACT(x FROM y) |
| registerIdentifierRole(FUNCTION, IdentifierRole.FUNCTION); // FUNCTION(n, x1, ..., x2) |
| registerIdentifierRole(INTERSECT, IdentifierRole.CLAUSE); |
| registerIdentifierRole(NULLS_FIRST, IdentifierRole.COMPLEMENT); |
| registerIdentifierRole(NULLS_LAST, IdentifierRole.COMPLEMENT); |
| registerIdentifierRole(ON, IdentifierRole.CLAUSE); // ON x |
| registerIdentifierRole(OPERATOR, IdentifierRole.FUNCTION); // FUNCTION(n, x1, ..., x2) |
| registerIdentifierRole(REGEXP, IdentifierRole.COMPOUND_FUNCTION); // x REGEXP y |
| registerIdentifierRole(SQL, IdentifierRole.FUNCTION); // FUNCTION(n, x1, ..., x2) |
| registerIdentifierRole(TABLE, IdentifierRole.FUNCTION); // TABLE('TABLE_NAME') |
| registerIdentifierRole(UNION, IdentifierRole.CLAUSE); |
| |
| registerIdentifierVersion(CAST, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(COLUMN, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(EXCEPT, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(EXTRACT, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(FUNCTION, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(INTERSECT, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(NULLS_FIRST, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(NULLS_LAST, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(ON, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(OPERATOR, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(REGEXP, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(SQL, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(TABLE, JPAVersion.VERSION_2_1); |
| registerIdentifierVersion(UNION, JPAVersion.VERSION_2_1); |
| |
| // Partial identifiers |
| registerIdentifierRole("NULLS", IdentifierRole.CLAUSE); // Part of NULLS FIRST, NULLS LAST |
| registerIdentifierRole("FIRST", IdentifierRole.CLAUSE); // Part of NULLS FIRST |
| registerIdentifierRole("LAST", IdentifierRole.CLAUSE); // Part of NULLS LAST |
| } |
| |
| @Override |
| public String toString() { |
| return "EclipseLink 2.4"; |
| } |
| } |