| /* |
| * 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 org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import java.util.*; |
| |
| /** |
| * This is used during the normalization process to allow for a single main expression traversal. |
| */ |
| public class ExpressionNormalizer { |
| |
| /** A new root expression can be made from joins being added to the original expression. */ |
| protected Expression additionalExpression; |
| |
| /** The statement being normalized. */ |
| protected SQLSelectStatement statement; |
| |
| /** Subselect expressions found in the course of normalization. */ |
| protected List<SubSelectExpression> subSelectExpressions; |
| |
| /** The session being normalized in. */ |
| protected AbstractSession session; |
| |
| /** Used to maintain identity of cloned expressions. */ |
| protected Map<Expression, Expression> clonedExpressions; |
| |
| /** |
| * Used to trigger adding additional join operations etc to the expression being processed instead of at the end of the where clause. |
| * Useful for dealing with Treat within an Or clause, as the type expression needs to be appended within the OR condition rather AND'd |
| * to the entire thing. |
| */ |
| protected boolean addAdditionalExpressionsWithinCurrrentExpressionContext = false; |
| /** Local expression from joins being added to the original expression. */ |
| protected Expression additionalLocalExpression; |
| |
| public ExpressionNormalizer(SQLSelectStatement statement) { |
| this.statement = statement; |
| } |
| |
| public Map<Expression, Expression> getClonedExpressions() { |
| return clonedExpressions; |
| } |
| |
| public void setClonedExpressions(Map<Expression, Expression> clonedExpressions) { |
| this.clonedExpressions = clonedExpressions; |
| } |
| |
| public void addAdditionalExpression(Expression theExpression) { |
| // This change puts a null check into every call, but is printing additional |
| // expressions in a meaningful order worth it? |
| additionalExpression = (additionalExpression == null) ? theExpression : additionalExpression.and(theExpression); |
| } |
| |
| /** |
| * INTERNAL: |
| * Remember this subselect so that it can be normalized after the enclosing |
| * select statement is. |
| */ |
| public void addSubSelectExpression(SubSelectExpression subSelectExpression) { |
| if (this.subSelectExpressions == null) { |
| this.subSelectExpressions = new ArrayList(4); |
| } |
| if (!this.subSelectExpressions.contains(subSelectExpression)) { |
| this.subSelectExpressions.add(subSelectExpression); |
| } |
| } |
| |
| public Expression getAdditionalExpression() { |
| return additionalExpression; |
| } |
| |
| public AbstractSession getSession() { |
| return session; |
| } |
| |
| public SQLSelectStatement getStatement() { |
| return statement; |
| } |
| |
| /** |
| * INTERNAL: |
| * Were subselect expressions found while normalizing the selection criteria? |
| * Assumes underlying collection is initialized on first add. |
| */ |
| public boolean encounteredSubSelectExpressions() { |
| return (subSelectExpressions != null); |
| } |
| |
| /** |
| * INTERNAL: |
| * Normalize all subselect expressions found in the course of normalizing the |
| * enclosing query. |
| * This method allows one to completely normalize the parent statement first |
| * (which should treat its sub selects as black boxes), and then normalize the |
| * subselects (which require full knowledge of the enclosing statement). |
| * This should make things clearer too, |
| * Assumes encounteredSubSelectExpressions() true. |
| * For CR#4223. |
| */ |
| public void normalizeSubSelects(Map clonedExpressions) { |
| for (SubSelectExpression next : this.subSelectExpressions) { |
| next.normalizeSubSelect(this, clonedExpressions); |
| } |
| } |
| |
| public void setAdditionalExpression(Expression additionalExpression) { |
| this.additionalExpression = additionalExpression; |
| } |
| |
| public void setSession(AbstractSession session) { |
| this.session = session; |
| } |
| |
| public void setStatement(SQLSelectStatement statement) { |
| this.statement = statement; |
| } |
| |
| /** |
| * Similar to addAdditionalExpression, this keeps a running expression used for joins so that they can be added locally within 'OR' |
| * predicates rather than to the entire where clause. If addAdditionalExpressionsWithinCurrrentExpressionContext is false, it will work |
| * the same as addAdditionalExpression |
| * @param theExpression |
| */ |
| public void addAdditionalLocalExpression(Expression theExpression) { |
| // This change puts a null check into every call, but is printing additional |
| // expressions in a meaningful order worth it? |
| if (addAdditionalExpressionsWithinCurrrentExpressionContext) { |
| additionalLocalExpression = (additionalLocalExpression == null) ? theExpression : additionalLocalExpression.and(theExpression); |
| } else { |
| additionalExpression = (additionalExpression == null) ? theExpression : additionalExpression.and(theExpression); |
| } |
| } |
| |
| /** |
| * INTERNAL |
| * This will return the localExpression if isLogicalExpression is false, otherwise it will check the addAdditionalExpressionsWithinCurrrentExpressionContext |
| * flag and clear additionalLocalExpression once adding it to the localExpression. |
| * @param localExpression |
| * @param isLogicalExpression |
| * @return |
| */ |
| public Expression processAdditionalLocalExpressions(Expression localExpression, boolean isLogicalExpression) { |
| if (!isLogicalExpression || !addAdditionalExpressionsWithinCurrrentExpressionContext) { |
| return localExpression; |
| } |
| Expression expToReturn = localExpression.and(additionalLocalExpression); |
| additionalLocalExpression = null; |
| |
| return expToReturn; |
| } |
| |
| public boolean isAddAdditionalExpressionsWithinCurrrentExpressionContext() { |
| return addAdditionalExpressionsWithinCurrrentExpressionContext; |
| } |
| |
| /** |
| * INTERNAL: |
| * Allows keeping track when the normalizer is within a logical OR statement, where additionalExpressions might need to be added to the local |
| * expression instead of at the end of the where clause. |
| * @param addAdditionalExpressionsWithinCurrrentExpressionContext |
| */ |
| public void setAddAdditionalExpressionsWithinCurrrentExpressionContext( |
| boolean addAdditionalExpressionsWithinCurrrentExpressionContext) { |
| this.addAdditionalExpressionsWithinCurrrentExpressionContext = addAdditionalExpressionsWithinCurrrentExpressionContext; |
| } |
| } |