org.eclipse.persistence.jpa.jpql.parser.AsOfClause Maven / Gradle / Ivy
Show all versions of eclipselink Show documentation
/*
* Copyright (c) 2012, 2018 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.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.WordParser;
/**
* An AS OF
clause is part of a flashback query, which provides ways to view
* past states of database objects, or to return database objects to a previous state, without using
* traditional point-in-time recovery.
*
* Specify AS OF
to retrieve the single version of the rows returned by the
* query at a particular change number (SCN) or timestamp. If you specify SCN, then the expression
* must evaluate to a number. If you specify TIMESTAMP
, then the expression must
* evaluate to a timestamp value. Oracle Database returns rows as they existed at the specified
* system change number or time.
*
*
BNF: asof_clause ::= AS OF { SCN | TIMESTAMP } scalar_expression
*
* @version 2.5
* @since 2.5
* @author Pascal Filion
*/
public final class AsOfClause extends AbstractExpression {
/**
* The {@link Expression} representing the timestamp or change number.
*/
private AbstractExpression expression;
/**
* Determines whether a whitespace was found after either SCN or
* TIMESTAMP
.
*/
private boolean hasSpaceAfterCategory;
/**
* Determines whether a whitespace was found after AS OF.
*/
private boolean hasSpaceAfterIdentifier;
/**
* The actual identifier found in the string representation of the JPQL query.
*/
private String identifier;
/**
* The actual SCN
identifier found in the string representation of the
* JPQL query.
*/
private String scnIdentifier;
/**
* The actual TIMESTAMP
identifier found in the string representation of the
* JPQL query.
*/
private String timestampIdentifier;
/**
* Creates a new AsOfClause
.
*
* @param parent The parent of this expression
*/
public AsOfClause(AbstractExpression parent) {
super(parent, AS_OF);
}
/**
* {@inheritDoc}
*/
public void accept(ExpressionVisitor visitor) {
acceptUnknownVisitor(visitor);
}
/**
* {@inheritDoc}
*/
public void acceptChildren(ExpressionVisitor visitor) {
getExpression().accept(visitor);
}
/**
* {@inheritDoc}
*/
@Override
protected void addChildrenTo(Collection children) {
children.add(getExpression());
}
/**
* {@inheritDoc}
*/
@Override
protected void addOrderedChildrenTo(List children) {
// 'AS OF'
children.add(buildStringExpression(AS_OF));
if (hasSpaceAfterIdentifier) {
children.add(buildStringExpression(SPACE));
}
// 'SCN'
if (scnIdentifier != null) {
children.add(buildStringExpression(SCN));
}
// 'TIMESTAMP'
else if (timestampIdentifier != null) {
children.add(buildStringExpression(TIMESTAMP));
}
if (hasSpaceAfterCategory) {
children.add(buildStringExpression(SPACE));
}
// Expression
if (expression != null) {
children.add(expression);
}
}
/**
* {@inheritDoc}
*/
@Override
public JPQLQueryBNF findQueryBNF(Expression expression) {
if ((this.expression != null) && this.expression.isAncestor(expression)) {
return getQueryBNF(ScalarExpressionBNF.ID);
}
return super.findQueryBNF(expression);
}
/**
* Returns the actual AS OF identifier found in the string representation of the JPQL
* query, which has the actual case that was used.
*
* @return The AS OF identifier that was actually parsed
*/
public String getActualIdentifier() {
return identifier;
}
/**
* Returns the actual SCN identifier found in the string representation of the JPQL query,
* which has the actual case that was used.
*
* @return The SCN identifier that was actually parsed, or an empty string if it was not parsed
*/
public String getActualScnIdentifier() {
return (scnIdentifier != null) ? scnIdentifier : ExpressionTools.EMPTY_STRING;
}
/**
* Returns the actual TIMESTAMP identifier found in the string representation of the JPQL
* query, which has the actual case that was used.
*
* @return The TIMESTAMP identifier that was actually parsed, or an empty string if it was
* not parsed
*/
public String getActualTimestampIdentifier() {
return (timestampIdentifier != null) ? timestampIdentifier : ExpressionTools.EMPTY_STRING;
}
/**
* Returns the {@link Expression} representing the timestamp or change number.
*
* @return The {@link Expression} that was parsed representing the timestamp or change number
*/
public Expression getExpression() {
if (expression == null) {
expression = buildNullExpression();
}
return expression;
}
/**
* {@inheritDoc}
*/
public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(AsOfClauseBNF.ID);
}
/**
* Determines whether the {@link Expression} representing the timestamp or change number was
* parsed or not.
*
* @return true
if the timestamp or change number was parsed; false
otherwise
*/
public boolean hasExpression() {
return expression != null &&
!expression.isNull();
}
/**
* Determines whether the identifier SCN was part of the query.
*
* @return true
if the identifier SCN was parsed; false
otherwise
*/
public boolean hasScn() {
return scnIdentifier != null;
}
/**
* Determines whether a whitespace was found after either SCN or TIMESTAMP
.
*
* @return true
if there was a whitespace after SCN or TIMESTAMP
;
* false
otherwise
*/
public boolean hasSpaceAfterCategory() {
return hasSpaceAfterCategory;
}
/**
* Determines whether a whitespace was found after AS OF.
*
* @return true
if there was a whitespace after AS OF; false
otherwise
*/
public boolean hasSpaceAfterIdentifier() {
return hasSpaceAfterIdentifier;
}
/**
* Determines whether the identifier TIMESTAMP was part of the query.
*
* @return true
if the identifier TIMESTAMP was parsed; false
otherwise
*/
public boolean hasTimestamp() {
return timestampIdentifier != null;
}
/**
* {@inheritDoc}
*/
@Override
protected void parse(WordParser wordParser, boolean tolerant) {
// 'AS OF'
identifier = wordParser.moveForwardIgnoreWhitespace(AS_OF);
hasSpaceAfterIdentifier = wordParser.skipLeadingWhitespace() > 0;
// 'SCN'
if (wordParser.startsWithIdentifier(SCN)) {
scnIdentifier = wordParser.moveForward(SCN);
hasSpaceAfterCategory = wordParser.skipLeadingWhitespace() > 0;
}
// 'TIMESTAMP'
else if (wordParser.startsWithIdentifier(TIMESTAMP)) {
timestampIdentifier = wordParser.moveForward(TIMESTAMP);
hasSpaceAfterCategory = wordParser.skipLeadingWhitespace() > 0;
}
// Expression
expression = parse(wordParser, ScalarExpressionBNF.ID, tolerant);
}
/**
* {@inheritDoc}
*/
@Override
protected void toParsedText(StringBuilder writer, boolean actual) {
// 'AS OF'
writer.append(actual ? identifier : AS_OF);
if (hasSpaceAfterIdentifier) {
writer.append(SPACE);
}
// 'SCN'
if (scnIdentifier != null) {
writer.append(actual ? scnIdentifier : SCN);
}
// 'TIMESTAMP'
if (timestampIdentifier != null) {
writer.append(actual ? timestampIdentifier : TIMESTAMP);
}
if (hasSpaceAfterCategory) {
writer.append(SPACE);
}
// Expression
if (expression != null) {
expression.toParsedText(writer, actual);
}
}
}