org.eclipse.persistence.jpa.jpql.parser.AbstractSelectStatement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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 java.util.Collection;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.WordParser;
/**
* A query is an operation that retrieves data from one or more tables or views. In this reference,
* a top-level SELECT
statement is called a query, and a query nested within
* another SQL statement is called a subquery.
*
* @see SelectStatement
* @see SimpleSelectStatement
*
* @version 2.5
* @since 2.3
* @author Pascal Filion
*/
public abstract class AbstractSelectStatement extends AbstractExpression {
/**
* The FROM
clause of this select statement.
*/
private AbstractExpression fromClause;
/**
* The GROUP BY
clause of this select statement.
*/
private AbstractExpression groupByClause;
/**
* Determines whether there is a whitespace after the identifier FROM
.
*/
private boolean hasSpaceAfterFrom;
/**
* Determines whether there is a whitespace after the identifier GROUP BY
.
*/
private boolean hasSpaceAfterGroupBy;
/**
* Determines whether there is a whitespace after the identifier SELECT
.
*/
private boolean hasSpaceAfterSelect;
/**
* Determines whether there is a whitespace after the identifier WHERE
.
*/
private boolean hasSpaceAfterWhere;
/**
* The HAVING
clause of this select statement.
*/
private AbstractExpression havingClause;
/**
* The SELECT
clause of this select statement.
*/
private AbstractExpression selectClause;
/**
* The WHERE
clause of this select statement.
*/
private AbstractExpression whereClause;
/**
* Creates a new AbstractSelectStatement
.
*
* @param parent The parent of this expression
*/
protected AbstractSelectStatement(AbstractExpression parent) {
super(parent);
}
@Override
public void acceptChildren(ExpressionVisitor visitor) {
getSelectClause().accept(visitor);
getFromClause().accept(visitor);
getWhereClause().accept(visitor);
getGroupByClause().accept(visitor);
getHavingClause().accept(visitor);
}
@Override
protected void addChildrenTo(Collection children) {
children.add(getSelectClause());
children.add(getFromClause());
children.add(getWhereClause());
children.add(getGroupByClause());
children.add(getHavingClause());
}
@Override
protected void addOrderedChildrenTo(List children) {
// SELECT clause
if (selectClause != null) {
children.add(selectClause);
}
// Space between SELECT and FROM clauses
if (hasSpaceAfterSelect) {
children.add(buildStringExpression(SPACE));
}
// FROM clause
if (fromClause != null) {
children.add(fromClause);
}
// Space between the FROM clause and an optional clause
if (hasSpaceAfterFrom) {
children.add(buildStringExpression(SPACE));
}
// WHERE clause
if (whereClause != null) {
children.add(whereClause);
}
// Space between WHERE clause and another optional clause
if (hasSpaceAfterWhere) {
children.add(buildStringExpression(SPACE));
}
// GROUP BY clause
if (groupByClause != null) {
children.add(groupByClause);
}
// Space between GROUP BY clause and another optional clause
if (hasSpaceAfterGroupBy) {
children.add(buildStringExpression(SPACE));
}
// HAVING clause
if (havingClause != null) {
children.add(havingClause);
}
}
/**
* Creates the expression representing the from clause of this select statement.
*
* @return A new from clause, null
can't be returned
*/
protected abstract AbstractFromClause buildFromClause();
/**
* Creates the expression representing the select clause of this select statement.
*
* @return A new from clause, null
can't be returned
*/
protected abstract AbstractSelectClause buildSelectClause();
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if ((selectClause != null) && selectClause.isAncestor(expression)) {
return selectClause.getQueryBNF();
}
if ((fromClause != null) && fromClause.isAncestor(expression)) {
return fromClause.getQueryBNF();
}
if ((whereClause != null) && whereClause.isAncestor(expression)) {
return whereClause.getQueryBNF();
}
if ((groupByClause != null) && groupByClause.isAncestor(expression)) {
return groupByClause.getQueryBNF();
}
if ((havingClause != null) && havingClause.isAncestor(expression)) {
return havingClause.getQueryBNF();
}
return super.findQueryBNF(expression);
}
/**
* Returns the {@link Expression} representing the FROM clause.
*
* @return The expression representing the FROM clause
*/
public final Expression getFromClause() {
if (fromClause == null) {
fromClause = buildNullExpression();
}
return fromClause;
}
/**
* Returns the {@link Expression} representing the GROUP BY clause.
*
* @return The expression representing the GROUP BY clause
*/
public final Expression getGroupByClause() {
if (groupByClause == null) {
groupByClause = buildNullExpression();
}
return groupByClause;
}
/**
* Returns the {@link Expression} representing the HAVING clause.
*
* @return The expression representing the HAVING clause
*/
public final Expression getHavingClause() {
if (havingClause == null) {
havingClause = buildNullExpression();
}
return havingClause;
}
/**
* Returns the {@link AbstractSelectClause} representing the SELECT clause.
*
* @return The expression representing the SELECT clause
*/
public final Expression getSelectClause() {
if (selectClause == null) {
selectClause = buildNullExpression();
}
return selectClause;
}
/**
* Returns the {@link Expression} representing the WHERE clause.
*
* @return The expression representing the WHERE clause
*/
public final Expression getWhereClause() {
if (whereClause == null) {
whereClause = buildNullExpression();
}
return whereClause;
}
/**
* Determines whether the FROM clause was parsed or not.
*
* @return true
if the query that got parsed had the FROM clause
*/
public final boolean hasFromClause() {
return fromClause != null &&
!fromClause.isNull();
}
/**
* Determines whether the GROUP BY clause was parsed or not.
*
* @return true
if the query that got parsed had the GROUP BY clause
*/
public final boolean hasGroupByClause() {
return groupByClause != null &&
!groupByClause.isNull();
}
/**
* Determines whether the HAVING clause was parsed or not.
*
* @return true
if the query that got parsed had the HAVING clause
*/
public final boolean hasHavingClause() {
return havingClause != null &&
!havingClause.isNull();
}
/**
* Determines whether the SELECT clause was parsed or not.
*
* @return true
if the query that got parsed had the HAVING clause
* @since 2.5
*/
public final boolean hasSelectClause() {
return selectClause != null &&
!selectClause.isNull();
}
/**
* Determines whether a whitespace was found after the FROM clause. In some cases, the
* space is owned by a child of the FROM clause.
*
* @return true
if there was a whitespace after the FROM clause and owned by
* this expression; false
otherwise
*/
public final boolean hasSpaceAfterFrom() {
return hasSpaceAfterFrom;
}
/**
* Determines whether a whitespace was found after the GROUP BY clause. In some cases, the
* space is owned by a child of the GROUP BY clause.
*
* @return true
if there was a whitespace after the GROUP BY clause and owned
* by this expression; false
otherwise
*/
public final boolean hasSpaceAfterGroupBy() {
return hasSpaceAfterGroupBy;
}
/**
* Determines whether a whitespace was found after the SELECT clause. In some cases, the
* space is owned by a child of the SELECT clause.
*
* @return true
if there was a whitespace after the SELECT clause and owned
* by this expression; false
otherwise
*/
public final boolean hasSpaceAfterSelect() {
return hasSpaceAfterSelect;
}
/**
* Determines whether a whitespace was found after the WHERE clause. In some cases, the
* space is owned by a child of the WHERE clause.
*
* @return true
if there was a whitespace after the WHERE clause and owned by
* this expression; false
otherwise
*/
public final boolean hasSpaceAfterWhere() {
return hasSpaceAfterWhere;
}
/**
* Determines whether the WHERE clause is defined.
*
* @return true
if the query that got parsed had the WHERE clause
*/
public final boolean hasWhereClause() {
return whereClause != null &&
!whereClause.isNull();
}
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// Parse 'SELECT' clause
if (wordParser.startsWithIdentifier(SELECT)) {
selectClause = buildSelectClause();
selectClause.parse(wordParser, tolerant);
hasSpaceAfterSelect = wordParser.skipLeadingWhitespace() > 0;
}
// Parse 'FROM' clause
if (wordParser.startsWithIdentifier(FROM)) {
fromClause = buildFromClause();
fromClause.parse(wordParser, tolerant);
hasSpaceAfterFrom = wordParser.skipLeadingWhitespace() > 0;
}
// Parse 'WHERE' clause
if (wordParser.startsWithIdentifier(WHERE)) {
whereClause = new WhereClause(this);
whereClause.parse(wordParser, tolerant);
hasSpaceAfterWhere = wordParser.skipLeadingWhitespace() > 0;
}
// Parse 'GROUP BY' clause
if (wordParser.startsWithIdentifier(GROUP_BY)) {
groupByClause = new GroupByClause(this);
groupByClause.parse(wordParser, tolerant);
hasSpaceAfterGroupBy = wordParser.skipLeadingWhitespace() > 0;
}
// Parse 'HAVING' clause
if (wordParser.startsWithIdentifier(HAVING)) {
havingClause = new HavingClause(this);
havingClause.parse(wordParser, tolerant);
}
if (!wordParser.isTail() && !shouldManageSpaceAfterClause()) {
if (hasSpaceAfterFrom &&
whereClause == null &&
groupByClause == null &&
havingClause == null) {
hasSpaceAfterFrom = false;
wordParser.moveBackward(1);
}
else if (hasSpaceAfterWhere &&
groupByClause == null &&
havingClause == null) {
hasSpaceAfterWhere = false;
wordParser.moveBackward(1);
}
else if (hasSpaceAfterGroupBy &&
havingClause == null) {
hasSpaceAfterGroupBy = false;
wordParser.moveBackward(1);
}
}
}
/**
* Determines whether the whitespace following the HAVING
clause should be
* managed by this expression or not.
*
* @return true
by default to keep the whitespace part of this expression;
* false
to let the parent handle it
*/
protected boolean shouldManageSpaceAfterClause() {
return true;
}
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
// SELECT clause
if (selectClause != null) {
selectClause.toParsedText(writer, actual);
}
if (hasSpaceAfterSelect) {
writer.append(SPACE);
}
// FROM clause
if (fromClause != null) {
fromClause.toParsedText(writer, actual);
}
if (hasSpaceAfterFrom) {
writer.append(SPACE);
}
// WHERE clause
if (whereClause != null) {
whereClause.toParsedText(writer, actual);
}
if (hasSpaceAfterWhere) {
writer.append(SPACE);
}
// GROUP BY clause
if (groupByClause != null) {
groupByClause.toParsedText(writer, actual);
}
if (hasSpaceAfterGroupBy) {
writer.append(SPACE);
}
// HAVING clause
if (havingClause != null) {
havingClause.toParsedText(writer, actual);
}
}
}