All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.jpa.jpql.parser.AsOfClause Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * 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); } } }