/******************************************************************************* * Copyright (c) 1998, 2015 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 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; } }