blob: c5665bdc765d5770f76ca522792be29278806d1b [file] [log] [blame]
/*
* 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 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-337 - Java Persistence 2.0</a> and the additional
* support provided by EclipseLink 2.1.</p>
*
* The BNFs of the additional support are the following:
*
* <pre><code> join ::= join_spec { join_association_path_expression | join_treat_association_path_expression } [AS] identification_variable
*
* join_treat_association_path_expression ::= TREAT(join_association_path_expression AS entity_type_literal)
*
* func_expression ::= FUNC(string_literal {, func_item}*)
*
* func_item ::= new_value
*
* between_expression ::= scalar_expression [NOT] BETWEEN scalar_expression AND scalar_expression
*
* in_expression ::= in_expression_expression [NOT] IN { ( in_item {, in_item}* ) | (subquery) | collection_valued_input_parameter }
*
* in_expression_expression ::= { state_field_path_expression | type_discriminator |
* single_valued_input_parameter | identification_variable |
* scalar_expression }
*
* in_item ::= literal | single_valued_input_parameter | scalar_expression
*
* scalar_expression ::= arithmetic_expression |
* ...
*
* pattern_value ::= scalar_expression | arithmetic_expression
*
* escape_character ::= scalar_expression
*
* functions_returning_numerics ::= LENGTH(scalarExpression) |
* LOCATE(scalarExpression, scalarExpression[, scalarExpression]) |
* MOD(scalarExpression, scalarExpression) |
* SQRT(scalarExpression)
* func_expression |
* ...
*
* functions_returning_strings ::= CONCAT(scalar_expression {, scalar_expression }+) |
* SUBSTRING(scalar_expression, scalar_expression [, scalar_expression]) |
* LOWER(scalar_expression) |
* UPPER(scalar_expression) |
* func_expression |
* ...
*
* orderby_item ::= state_field_path_expression | result_variable | scalar_expression [ ASC | DESC ]
*
* groupby_item ::= single_valued_path_expression | identification_variable | scalar_expression
*
* aggregate_expression ::= { AVG | MAX | MIN | SUM | COUNT } ([DISTINCT] scalar_expression)</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_1 extends AbstractJPQLGrammar {
/**
* The singleton instance of this {@link EclipseLinkJPQLGrammar2_1}.
*/
private static final JPQLGrammar INSTANCE = new EclipseLinkJPQLGrammar2_1();
/**
* The EclipseLink version, which is 2.1.
*/
public static final EclipseLinkVersion VERSION = EclipseLinkVersion.VERSION_2_1;
/**
* Creates a new <code>EclipseLinkJPQLGrammar2_1</code>.
*/
public EclipseLinkJPQLGrammar2_1() {
super();
}
/**
* Creates a new <code>EclipseLinkJPQLGrammar2_1</code>.
*
* @param jpqlGrammar The {@link JPQLGrammar} to extend with the content of this one without
* instantiating the base {@link JPQLGrammar}
*/
private EclipseLinkJPQLGrammar2_1(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_1(jpqlGrammar);
}
/**
* Returns the singleton instance of this class.
*
* @return The {@link EclipseLinkJPQLGrammar2_1}
*/
public static JPQLGrammar instance() {
return INSTANCE;
}
@Override
protected JPQLGrammar buildBaseGrammar() {
// First build the JPQL 2.0 grammar
JPQLGrammar2_0 jpqlGrammar = new JPQLGrammar2_0();
// Extend it by adding the EclipseLink 2.0 additional support
EclipseLinkJPQLGrammar2_0.extend(jpqlGrammar);
return jpqlGrammar;
}
@Override
public JPAVersion getJPAVersion() {
return JPAVersion.VERSION_2_0;
}
@Override
public String getProvider() {
return DefaultEclipseLinkJPQLGrammar.PROVIDER_NAME;
}
@Override
public String getProviderVersion() {
return VERSION.getVersion();
}
@Override
protected void initializeBNFs() {
// Add new query BNF
registerBNF(new FunctionExpressionBNF());
registerBNF(new FunctionItemBNF());
registerBNF(new TreatExpressionBNF());
// Extend the query BNF to add support new JPQL identifiers
addChildBNF(FunctionsReturningNumericsBNF.ID, FunctionExpressionBNF.ID);
addChildBNF(JoinAssociationPathExpressionBNF.ID, TreatExpressionBNF.ID);
// Extend to support scalarExpression
addChildBNF(GroupByItemBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(LikeExpressionEscapeCharacterBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalAggregateFunctionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalConcatExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalCountBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalLengthExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalLocateStringExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalLocateThirdExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalLowerExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalModExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalOrderByItemBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalSqrtExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalSubstringPositionExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalSubstringStringExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalUpperExpressionBNF.ID, ScalarExpressionBNF.ID);
// Extend to support scalarOrSubSelectExpression
addChildBNF(InternalBetweenExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InternalBetweenExpressionBNF.ID, ArithmeticExpressionBNF.ID);
addChildBNF(InExpressionExpressionBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InExpressionItemBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(InExpressionItemBNF.ID, ArithmeticExpressionBNF.ID);
addChildBNF(PatternValueBNF.ID, ScalarExpressionBNF.ID);
addChildBNF(PatternValueBNF.ID, ArithmeticExpressionBNF.ID);
}
@Override
protected void initializeExpressionFactories() {
registerFactory(new FunctionExpressionFactory(FunctionExpressionFactory.ID, FUNC));
registerFactory(new TreatExpressionFactory());
}
@Override
protected void initializeIdentifiers() {
// Expand ComparisonExpression to support !=
addIdentifiers(ComparisonExpressionFactory.ID, NOT_EQUAL);
registerIdentifierRole(FUNC, IdentifierRole.FUNCTION); // FUNC(n, x1, ..., x2)
registerIdentifierRole(NOT_EQUAL, IdentifierRole.AGGREGATE); // x != y
registerIdentifierRole(TREAT, IdentifierRole.FUNCTION); // TREAT(x AS y)
registerIdentifierVersion(FUNC, JPAVersion.VERSION_2_0);
registerIdentifierVersion(NOT_EQUAL, JPAVersion.VERSION_2_0);
registerIdentifierVersion(TREAT, JPAVersion.VERSION_2_0);
}
@Override
public String toString() {
return "EclipseLink 2.1";
}
}