001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
005: *
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common Development
009: * and Distribution License("CDDL") (collectively, the "License"). You
010: * may not use this file except in compliance with the License. You can obtain
011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
013: * language governing permissions and limitations under the License.
014: *
015: * When distributing the software, include this License Header Notice in each
016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
017: * Sun designates this particular file as subject to the "Classpath" exception
018: * as provided by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the License
020: * Header, with the fields enclosed by brackets [] replaced by your own
021: * identifying information: "Portions Copyrighted [year]
022: * [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * If you wish your version of this file to be governed by only the CDDL or
027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
028: * elects to include this software in this distribution under the [CDDL or GPL
029: * Version 2] license." If you don't indicate a single choice of license, a
030: * recipient has the option to distribute your version of this file under
031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
032: * its licensees as provided above. However, if you add GPL Version 2 code
033: * and therefore, elected the GPL Version 2 license, then the option applies
034: * only if the new code is made subject to such option by the copyright
035: * holder.
036: */
037: package oracle.toplink.essentials.internal.parsing;
038:
039: import java.util.Hashtable;
040: import java.util.Iterator;
041: import java.util.Set;
042:
043: import oracle.toplink.essentials.expressions.Expression;
044: import oracle.toplink.essentials.internal.sessions.AbstractSession;
045:
046: /**
047: * INTERNAL:
048: * An extension of GenerationContext the provides SELECT specfic behavior.
049: * Used when building the query features that are not usable in other types of queries
050: */
051: public class SelectGenerationContext extends GenerationContext {
052: //if a 1:1 is SELECTed in the EJBQL, then we need to use parallel expressions
053: //with each ExpressionBuilder created using "new ExpressionBuilder(MyClass.class)"
054: private boolean useParallelExpressions = false;
055:
056: //BUG 3105651: If a variable is SELECTed, and it's in an ORDER BY, then
057: //we want the ExpressionBuilder to be instantiated using an empty constructor
058: private boolean shouldCheckSelectNodeBeforeResolving = false;
059: private boolean isNotIndicatedInMemberOf = false;
060:
061: //If a NOT MEMBER OF is encountered, we need to store the MEMBER OF
062: //so that the right side of the member of can use the stored expression
063: //from the left
064: private MemberOfNode memberOfNode = null;
065:
066: //Do we want to use outer joins? get("address") vs getAllowingNull("address")
067: private boolean shouldUseOuterJoins = false;
068:
069: //Outer SelectGenerationContext
070: private GenerationContext outer = null;
071:
072: public SelectGenerationContext() {
073: super ();
074: }
075:
076: /**
077: * Constructor used to create the context for a subquery.
078: */
079: public SelectGenerationContext(GenerationContext outer,
080: ParseTree newParseTree) {
081: this (outer.getParseTreeContext(), outer.getSession(),
082: newParseTree);
083: this .outer = outer;
084: }
085:
086: public SelectGenerationContext(ParseTreeContext newContext,
087: AbstractSession newSession, ParseTree newParseTree) {
088: super (newContext, newSession, newParseTree);
089:
090: //indicate if we want parallel expressions or not
091: useParallelExpressions = this .computeUseParallelExpressions();
092: }
093:
094: //Set and get the contained MemberOfNode. This is for handling NOT MEMBER OF.
095: public void setMemberOfNode(MemberOfNode newMemberOfNode) {
096: memberOfNode = newMemberOfNode;
097: }
098:
099: public MemberOfNode getMemberOfNode() {
100: return memberOfNode;
101: }
102:
103: private boolean computeUseParallelExpressions() {
104: boolean computedUseParallelExpressions;
105:
106: //use parallel expressions if I have a 1:1 selected, and the same class isn't
107: //declared in the FROM
108: computedUseParallelExpressions = ((SelectNode) this .parseTree
109: .getQueryNode()).hasOneToOneSelected(this );
110: //check if they've SELECTed a variable declared in the IN clause in the FROM,
111: //or they've mapped more than one variable to the same type in the FROM
112: computedUseParallelExpressions = computedUseParallelExpressions
113: || ((SelectNode) this .parseTree.getQueryNode())
114: .isVariableInINClauseSelected(this )
115: || this .parseTree.getContext()
116: .hasMoreThanOneVariablePerType()
117: || this .parseTree.getContext()
118: .hasMoreThanOneAliasInFrom();
119: return computedUseParallelExpressions;
120: }
121:
122: //Answer true if we need to use parallel expressions
123: //This will be the case if a 1:1 is SELECTed in the EJBQL.
124: public boolean useParallelExpressions() {
125: return useParallelExpressions;
126: }
127:
128: //Indicate that we want VariableNodes to check if they're
129: //SELECTed first, to determine how to instantiate the ExpressionBuilder
130: public void checkSelectNodeBeforeResolving(boolean shouldCheck) {
131: shouldCheckSelectNodeBeforeResolving = shouldCheck;
132: }
133:
134: //Answer true if we want VariableNodes to check if they're
135: //SELECTed first, to determine how to instantiate the ExpressionBuilder
136: public boolean shouldCheckSelectNodeBeforeResolving() {
137: return shouldCheckSelectNodeBeforeResolving;
138: }
139:
140: //Answer true if we should use outer joins in our get() (vs getAllowingNull())
141: public boolean shouldUseOuterJoins() {
142: return shouldUseOuterJoins;
143: }
144:
145: public void useOuterJoins() {
146: shouldUseOuterJoins = true;
147: }
148:
149: public void dontUseOuterJoins() {
150: shouldUseOuterJoins = false;
151: }
152:
153: //Answer true if we have a MemberOfNode contained. This is for handling NOT MEMBER OF
154: public boolean hasMemberOfNode() {
155: return memberOfNode != null;
156: }
157:
158: /** */
159: public GenerationContext getOuterContext() {
160: return outer;
161: }
162:
163: /**
164: * Iterate the set of variables declared in an outer scope and
165: * connect the inner varaible expression with the outer one.
166: */
167: public Expression joinVariables(Set variables) {
168: if ((outer == null) || (variables == null)
169: || variables.isEmpty()) {
170: // not an inner query or no variables to join
171: return null;
172: }
173: Expression expr = null;
174: for (Iterator i = variables.iterator(); i.hasNext();) {
175: String name = (String) i.next();
176: VariableNode var = new VariableNode(name);
177: Expression innerExpr = var.generateExpression(this );
178: Expression outerExpr = var.generateExpression(outer);
179: Expression join = innerExpr.equal(outerExpr);
180: expr = var.appendExpression(expr, join);
181: }
182: return expr;
183: }
184: }
|