blob: 9c41d71286e181f15592220e6c4b690f2e2a3039 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.internal.expressions;
import java.io.*;
import java.util.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.queries.ReportItem;
/**
* Allow a table expression to be created on a sub-select to define a sub-select in the from clause.
*/
public class FromSubSelectExpression extends TableExpression {
/** Allows a sub-select to be defined from clause. */
protected SubSelectExpression subSelect;
public FromSubSelectExpression() {
super();
}
public FromSubSelectExpression(SubSelectExpression subSelect) {
super();
this.subSelect = subSelect;
this.table = new SubSelectDatabaseTable(subSelect);
}
/**
* INTERNAL:
* Return if the expression is equal to the other.
* This is used to allow dynamic expression's SQL to be cached.
* From sub-selects are too complex to cache, so use identity.
*/
@Override
public boolean equals(Object object) {
return this == object;
}
/**
* INTERNAL:
* Compute a consistent hash-code for the expression.
*/
@Override
public int computeHashCode() {
return System.identityHashCode(this);
}
/**
* INTERNAL:
* Used for debug printing.
*/
@Override
public String descriptionOfNodeType() {
return "FromSubSelect";
}
/**
* This is used by sub-selects in the from clause to define a virtual table,
* 'get' allows one of the sub-selected attributes to be aliased without using the field name.
*/
public Expression get(String alias) {
FromAliasExpression aliasExpression = new FromAliasExpression(alias, this);
return aliasExpression;
}
/**
* INTERNAL:
* Normalize the expression into a printable structure.
* Any joins must be added to form a new root.
*/
@Override
public Expression normalize(ExpressionNormalizer normalizer) {
if (this.subSelect != null) {
// Each item that is a function must have an alias defined for it.
for (ReportItem item : this.subSelect.getSubQuery().getItems()) {
if (!item.getAttributeExpression().isQueryKeyExpression()) {
item.setAttributeExpression(item.getAttributeExpression().as(item.getName()));
}
}
// Need to force the sub-slect to normalize instead of deferring.
this.subSelect.normalizeSubSelect(normalizer, normalizer.getClonedExpressions());
}
return super.normalize(normalizer);
}
/**
* INTERNAL:
* Also iterate over the sub-select if present.
*/
@Override
public void iterateOn(ExpressionIterator iterator) {
super.iterateOn(iterator);
if (this.subSelect != null) {
this.subSelect.iterateOn(iterator);
}
}
/**
* INTERNAL:
* Also copy over the sub-select if present.
*/
@Override
protected void postCopyIn(Map alreadyDone) {
super.postCopyIn(alreadyDone);
if (this.subSelect != null) {
this.subSelect = (SubSelectExpression)this.subSelect.copiedVersionFrom(alreadyDone);
this.table = new SubSelectDatabaseTable(subSelect);
}
}
/**
* INTERNAL:
* This expression is built on a different base than the one we want. Rebuild it and
* return the root of the new tree
*/
@Override
public Expression rebuildOn(Expression newBase) {
Expression newLocalBase = getBaseExpression().rebuildOn(newBase);
return newLocalBase.getAlias(this.subSelect.rebuildOn(newBase));
}
/**
* INTERNAL:
* Rebuild myself against the base, with the values of parameters supplied by the context
* expression. This is used for transforming a standalone expression (e.g. the join criteria of a mapping)
* into part of some larger expression. You normally would not call this directly, instead calling twist
* See the comment there for more details"
*/
@Override
public Expression twistedForBaseAndContext(Expression newBase, Expression context, Expression oldBase) {
Expression twistedBase = getBaseExpression().twistedForBaseAndContext(newBase, context, oldBase);
return twistedBase.getAlias(this.subSelect.twistedForBaseAndContext(newBase, context, oldBase));
}
/**
* INTERNAL:
* Used to print a debug form of the expression tree.
*/
@Override
public void writeDescriptionOn(BufferedWriter writer) throws IOException {
this.subSelect.writeDescriptionOn(writer);
writer.write(tableAliasesDescription());
}
/**
* INTERNAL:
* Any table should use the sub-selects alias.
*/
@Override
public DatabaseTable aliasForTable(DatabaseTable table) {
return super.aliasForTable(getTable());
}
public SubSelectExpression getSubSelect() {
return subSelect;
}
public void setSubSelect(SubSelectExpression subSelect) {
this.subSelect = subSelect;
this.table = new SubSelectDatabaseTable(subSelect);
}
}