| /* |
| * Copyright (c) 1998, 2020 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 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. |
| */ |
| @Override |
| 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); |
| } |
| } |