You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2009/07/20 19:49:37 UTC

svn commit: r795934 [1/2] - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/jav...

Author: faywang
Date: Mon Jul 20 17:49:36 2009
New Revision: 795934

URL: http://svn.apache.org/viewvc?rev=795934&view=rev
Log:
OPENJPA-1185: commit subquery overhaul on behalf of Catalina

Added:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java   (with props)
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/NotContainsExpression.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Table.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Join.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestSubquery.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java Mon Jul 20 17:49:36 2009
@@ -30,7 +30,6 @@
 import java.util.Map;
 
 import org.apache.openjpa.event.LifecycleEventManager;
-import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
 import org.apache.openjpa.jdbc.kernel.exps.ExpContext;
 import org.apache.openjpa.jdbc.kernel.exps.GetColumn;
 import org.apache.openjpa.jdbc.kernel.exps.JDBCExpressionFactory;
@@ -46,20 +45,20 @@
 import org.apache.openjpa.jdbc.meta.FieldMapping;
 import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy;
 import org.apache.openjpa.jdbc.schema.Column;
-import org.apache.openjpa.jdbc.schema.ForeignKey;
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.jdbc.sql.DBDictionary;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.SQLExceptions;
 import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.jdbc.sql.SelectImpl;
 import org.apache.openjpa.jdbc.sql.Union;
 import org.apache.openjpa.kernel.ExpressionStoreQuery;
 import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.kernel.OrderingMergedResultObjectProvider;
-import org.apache.openjpa.kernel.QueryContext;
 import org.apache.openjpa.kernel.QueryHints;
 import org.apache.openjpa.kernel.exps.Constant;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.kernel.exps.ExpressionFactory;
 import org.apache.openjpa.kernel.exps.ExpressionParser;
 import org.apache.openjpa.kernel.exps.FilterListener;
@@ -143,11 +142,28 @@
     protected ExpressionFactory getExpressionFactory(ClassMetaData meta) {
         return new JDBCExpressionFactory((ClassMapping) meta);
     }
+    
+    private void resetSelect(Context ctx) {
+        List<Context> subselCtxs = ctx.getSubselContexts();
+        if (subselCtxs != null) {
+            for (Context subselCtx : subselCtxs) {
+                SelectImpl sel = (SelectImpl)subselCtx.getSelect();
+                sel.reset();
+                resetSelect(subselCtx);
+            }
+        }
+    }
 
     protected ResultObjectProvider executeQuery(Executor ex,
         ClassMetaData base, ClassMetaData[] metas, boolean subclasses,
         ExpressionFactory[] facts, QueryExpressions[] exps, Object[] params,
         Range range) {
+        Context expCtx = exps[0].ctx(); 
+        if (expCtx != null) {
+            expCtx.resetAliasCount();
+            expCtx.setSelect(null);
+            resetSelect(expCtx);
+        }
         if (metas.length > 1 && exps[0].isAggregate())
             throw new UserException(Localizer.forPackage(JDBCStoreQuery.class).
                 get("mult-mapping-aggregate", Arrays.asList(metas)));
@@ -449,6 +465,13 @@
     private Number executeBulkOperation(ClassMetaData[] metas,
         boolean subclasses, ExpressionFactory[] facts, QueryExpressions[] exps,
         Object[] params, Map updates) {
+        Context expCtx = exps[0].ctx(); 
+        if (ctx != null) {
+            expCtx.resetAliasCount();
+            expCtx.setSelect(null);
+            resetSelect(expCtx);
+        }
+        
         // we cannot execute a bulk delete statement when have mappings in
         // multiple tables, so indicate we want to use in-memory with null
         ClassMapping[] mappings = (ClassMapping[]) metas;

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/AbstractVal.java Mon Jul 20 17:49:36 2009
@@ -114,5 +114,9 @@
     public Path getPath() {
         return null;
     }
+    
+    public String getName() {
+        return null;
+    }    
 }
 

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ConstPath.java Mon Jul 20 17:49:36 2009
@@ -27,6 +27,7 @@
 import org.apache.openjpa.kernel.Broker;
 import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.kernel.exps.ExpressionVisitor;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
@@ -217,4 +218,14 @@
     public XMLMetaData getXmlMapping() {
         return null;
     }
+
+    public void setSchemaAlias(String schemaAlias) {
+    }
+    
+    public String getSchemaAlias() {
+        return null;
+    }
+    
+    public void setSubqueryContext(Context conext) {
+    }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java Mon Jul 20 17:49:36 2009
@@ -167,7 +167,8 @@
     }
 
     public Expression not(Expression exp) {
-        if (HasContainsExpressionVisitor.hasContains(exp))
+        if (!(exp instanceof IsNotEmptyExpression) &&
+            HasContainsExpressionVisitor.hasContains(exp))
             return new NotContainsExpression((Exp) exp);
         return new NotExpression((Exp) exp);
     }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java Mon Jul 20 17:49:36 2009
@@ -36,6 +36,7 @@
     private Object _val;
     private int _ptype;
     private boolean _isRaw;
+    private Object _rawVal;
 
     /**
      * Constructor. Supply literal value.
@@ -46,6 +47,8 @@
     }
 
     public Class getType() {
+        if (_isRaw && _rawVal != null)
+            return Raw.class;
         return (_val == null) ? Object.class : _val.getClass();
     }
 
@@ -77,6 +80,10 @@
         _isRaw = isRaw;
     }
 
+    public Object getRawValue() {
+        return _rawVal;
+    }
+
     public ExpState initialize(Select sel, ExpContext ctx, int flags) {
         return new LitExpState();
     }
@@ -120,7 +127,7 @@
                 if (!isOrdinal)
                     value.append("'");
                 lstate.sqlValue = new Raw(value.toString());
-                setValue(lstate.sqlValue);
+                _rawVal = lstate.sqlValue;
             }
             sql.appendValue(lstate.sqlValue, lstate.getColumn(index));
         }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/NotContainsExpression.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/NotContainsExpression.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/NotContainsExpression.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/NotContainsExpression.java Mon Jul 20 17:49:36 2009
@@ -67,6 +67,10 @@
 
         Select sub = ctx.store.getSQLFactory().newSelect();
         sub.setParent(sel, null);
+        // this subselect has the same context as its parent
+        sub.setContext(sel.ctx());
+        // the context select should still belong to parent
+        sub.ctx().setSelect(sel);
         ExpState estate = _exp.initialize(sub, ctx, ((NotContainsExpState) 
             state).contains);
         sub.where(sub.and(null, estate.joins));

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java Mon Jul 20 17:49:36 2009
@@ -45,6 +45,7 @@
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.kernel.StoreContext;
 import org.apache.openjpa.kernel.exps.CandidatePath;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
@@ -82,6 +83,7 @@
     private boolean _cid = false;
     private FieldMetaData _xmlfield = null;
     private boolean _keyPath = false;
+    private String _schemaAlias = null;
 
     /**
      * Return a path starting with the 'this' ptr.
@@ -99,10 +101,12 @@
 
         PCPath other = var.getPCPath();
         Action action = new Action();
+        action.var = var.getName();
         if (other == null) {
             _type = UNBOUND_VAR;
             action.op = Action.UNBOUND_VAR;
             action.data = var;
+            _schemaAlias = var.getName();
         } else {
             // bound variable; copy path
             _type = UNACCESSED_VAR;
@@ -111,6 +115,7 @@
 
             action.op = Action.VAR;
             action.data = var.getName();
+            _schemaAlias = other._schemaAlias;
         }
         _actions.add(action);
         _cast = var.getType(); // initial type is var type
@@ -131,6 +136,22 @@
         _varName = sub.getCandidateAlias();
     }
 
+    public void setSchemaAlias(String schemaAlias) {
+        if (_schemaAlias == null) 
+            _schemaAlias = schemaAlias;
+    }
+
+    public String getSchemaAlias() {
+        return _schemaAlias;
+    }
+    
+    public void setSubqueryContext(Context context) {
+        Action action = lastFieldAction();
+        if (action == null)
+            return;
+        action.context = context;
+    }
+    
     /**
      * Set the path as a binding of the given variable.
      */
@@ -420,8 +441,7 @@
         if (act != null && act.op == Action.GET_XPATH)
             return ((XMLMetaData) act.data).getType();
         
-        FieldMetaData fld = act == null ? null :
-            (FieldMetaData) act.data;
+        FieldMetaData fld = (act == null) ? null : (FieldMetaData) act.data;
         boolean key = act != null && act.op == Action.GET_KEY;
         if (fld != null) {
             switch (fld.getDeclaredTypeCode()) {
@@ -457,6 +477,8 @@
         boolean forceOuter = false;
         ClassMapping rel = _candidate;
 
+        sel.setSchemaAlias(_schemaAlias);
+
         // iterate to the final field
         ClassMapping owner;
         ClassMapping from, to;
@@ -464,14 +486,27 @@
         Variable var;
         Iterator itr = (_actions == null) ? null : _actions.iterator();
         FieldMapping field = null;
+        Action prevaction = null;
+        boolean isCorrelatedPath = false;
+        boolean fromParentRootInSubselect = navigateFromParentRootInSubselect(sel);
+                
         while (itr != null && itr.hasNext()) {
             action = (Action) itr.next();
 
             // treat subqueries like variables for alias generation purposes
-            if (action.op == Action.VAR)
-                pstate.joins = pstate.joins.setVariable((String) action.data);
-            else if (action.op == Action.SUBQUERY)
+            if (action.op == Action.VAR) {
+                if (sel.getParent() != null && action.var != null &&
+                    prevaction != null && prevaction.data != null &&
+                    sel.ctx().getVariable(action.var) == null) {
+                    //System.out.println("Correlated action var="+action.var);
+                    isCorrelatedPath = true;
+                    pstate.joins = pstate.joins.setCorrelatedVariable(action.var);
+                } else 
+                    pstate.joins = pstate.joins.setVariable((String) action.data);
+            }
+            else if (action.op == Action.SUBQUERY) {
                 pstate.joins = pstate.joins.setSubselect((String) action.data);
+            }
             else if (action.op == Action.UNBOUND_VAR) {
                 // unbound vars are cross-joined to the candidate table
                 var = (Variable) action.data;
@@ -479,8 +514,16 @@
                 if (rel == null)
                 	throw new IllegalArgumentException(_loc.get(
                 	    "invalid-unbound-var", var.getName()).toString());
-                pstate.joins = pstate.joins.setVariable(var.getName());
-                pstate.joins = pstate.joins.crossJoin(_candidate.getTable(), 
+                	    
+                if (sel.getParent() != null && action.var != null &&
+                    sel.ctx().getVariable(action.var) == null) {
+                    //System.out.println("Correlated action var="+action.var);
+                    isCorrelatedPath = true;
+                    pstate.joins = pstate.joins.setCorrelatedVariable(var.getName());
+                } else                 
+                    pstate.joins = pstate.joins.setVariable(var.getName());
+
+                pstate.joins = pstate.joins.crossJoin(_candidate.getTable(),
                     rel.getTable());
             } else {
                 // move past the previous field, if any
@@ -496,6 +539,13 @@
                         pstate.cmpfield = field;
                         break;
                     }
+                    
+                    if (fromParentRootInSubselect) {
+                        isCorrelatedPath = true;
+                        pstate.joins = pstate.joins.setCorrelatedVariable(_schemaAlias);
+                        pstate.joins.setJoinContext(null);
+                    }
+                    
                     rel = traverseField(pstate, key, forceOuter, false);
                 }
 
@@ -543,6 +593,9 @@
                 if (action.op == Action.GET_XPATH)
                     break;
             }
+            prevaction = action;
+            if (prevaction != null && prevaction.context != null) 
+                pstate.joins = pstate.joins.setJoinContext(prevaction.context);
         }
         if (_varName != null)
             pstate.joins = pstate.joins.setVariable(_varName);
@@ -557,10 +610,56 @@
         if ((flags & JOIN_REL) != 0)
             joinRelation(pstate, key, forceOuter || (flags & FORCE_OUTER) != 0,
                 false);
+        if (isCorrelatedPath) {
+            // check if there are joins that belong to parent
+            pstate.joins.moveJoinsToParent();
+        }
+        pstate.joins.setJoinContext(null);
+        
+        if (_actions == null) {
+            String subqAlias = findSubqAlias(sel);
+            pstate.joins = pstate.joins.setSubselect(subqAlias);
+            pstate.joins.setCorrelatedVariable(_schemaAlias);
+        }
+        
         return pstate;
     }
+    
+    public String findSubqAlias(Select sel) {
+        Select pSel = sel.getParent();
+        if (pSel == null)
+            return null;
+        Context pCtx = pSel.ctx();
+        if (pCtx.subquery == null)
+            return null;
+        if (pCtx.getSchema(_schemaAlias) != null)
+            return ((SubQ)pCtx.subquery).getCandidateAlias();
+        return findSubqAlias(pSel);
+    }
 
     /**
+     * When a PCPath is in subselect, and it is simply a navigation
+     * from the parent root, the joins involved in this PCPath
+     * must happen in the main select.  
+     */
+    private boolean navigateFromParentRootInSubselect(Select sel) {
+        if (sel.getParent() == null)
+            return false;
+        Iterator itr = (_actions == null) ? null : _actions.iterator();
+        boolean navigateFromRoot = false;
+        boolean hasVar = false;
+        boolean startsWithSubquery = false;
+        while (itr != null && itr.hasNext()) {
+            Action action = (Action) itr.next();
+            if (action.op == Action.VAR) 
+                hasVar = true;
+            else if (action.op == Action.SUBQUERY)
+                startsWithSubquery = true;
+        }
+        return !hasVar && !startsWithSubquery && sel.ctx().getSchema(_schemaAlias) == null;
+    }
+    
+    /**
      * Return whether the given source field joins to the given target field.
      */
     private static boolean isJoinedField(FieldMapping src, boolean key, 
@@ -846,6 +945,8 @@
     public void appendTo(Select sel, ExpContext ctx, ExpState state, 
         SQLBuffer sql, int index) {
         Column col = getColumns(state)[index];
+        if (sel != null)
+            sel.setSchemaAlias(_schemaAlias);
 
         // if select is null, it means we are not aliasing columns
         // (e.g., during a bulk update)
@@ -977,6 +1078,8 @@
 
         public int op = -1;
         public Object data = null;
+        public String var = null;
+        public Context context = null;
 
         public String toString() {
             return op + "|" + data;

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java Mon Jul 20 17:49:36 2009
@@ -20,6 +20,7 @@
 
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.openjpa.jdbc.meta.ClassMapping;
@@ -29,8 +30,10 @@
 import org.apache.openjpa.jdbc.sql.Select;
 import org.apache.openjpa.kernel.exps.AbstractExpressionVisitor;
 import org.apache.openjpa.kernel.exps.Constant;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.kernel.exps.Expression;
 import org.apache.openjpa.kernel.exps.QueryExpressions;
+import org.apache.openjpa.kernel.exps.Subquery;
 import org.apache.openjpa.kernel.exps.Value;
 
 /**
@@ -43,6 +46,7 @@
     implements Serializable {
 
     private boolean _extent = false;
+    private Select _subselect = null;
 
     /**
      * Return true if we know the select to have on criteria; to be an extent.
@@ -53,6 +57,10 @@
         return _extent;
     }
 
+    public void setSubselect(Select subselect) {
+        _subselect = subselect;
+    }
+
     /**
      * Evaluate the expression, returning a new select and filling in any
      * associated expression state. Use {@link #select} to then select the data.
@@ -114,10 +122,25 @@
      */
     private Select newSelect(ExpContext ctx, Select parent,
         String alias, QueryExpressions exps, QueryExpressionsState state) {
-        Select sel = ctx.store.getSQLFactory().newSelect();
+        Select sel = parent != null ? _subselect
+            : ctx.store.getSQLFactory().newSelect();
         sel.setAutoDistinct((exps.distinct & exps.DISTINCT_AUTO) != 0);
         sel.setJoinSyntax(ctx.fetch.getJoinSyntax());
         sel.setParent(parent, alias);
+
+        if (sel.ctx() == null)
+            sel.setContext(exps.ctx());
+
+        if (parent == null && exps.ctx().getSubselContexts() != null) {
+            // this is the case subselect was created before parent got created
+            List<Context> subselCtxs = exps.ctx().getSubselContexts();
+            for (Context subselCtx : subselCtxs) {
+                Select subsel = (Select) subselCtx.getSelect();
+                Subquery subquery = subselCtx.getSubquery();
+                subsel.setParent(sel, subquery.getCandidateAlias());
+            }
+        }
+     
         initialize(sel, ctx, exps, state);
 
         if (!sel.getAutoDistinct()) {

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java Mon Jul 20 17:49:36 2009
@@ -20,6 +20,7 @@
 
 import java.sql.SQLException;
 
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
 import org.apache.openjpa.jdbc.meta.ClassMapping;
 import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
@@ -38,18 +39,19 @@
  *
  * @author Abe White
  */
-class SubQ
+public class SubQ
     extends AbstractVal
     implements Subquery {
 
     private final ClassMapping _candidate;
     private final boolean _subs;
-    private final String _alias;
+    private final String _subqAlias;
     private final SelectConstructor _cons = new SelectConstructor();
 
     private Class _type = null;
     private ClassMetaData _meta = null;
     private QueryExpressions _exps = null;
+    private Select _select = null;
 
     /**
      * Constructor. Supply candidate, whether subclasses are included in
@@ -58,7 +60,14 @@
     public SubQ(ClassMapping candidate, boolean subs, String alias) {
         _candidate = candidate;
         _subs = subs;
-        _alias = alias;
+        _subqAlias = alias;
+        _select = (((JDBCConfiguration) candidate.getMappingRepository().
+            getConfiguration()).getSQLFactoryInstance().newSelect());
+        _cons.setSubselect(_select);
+    }
+
+    public Object getSelect() {
+        return _select;
     }
 
     /**
@@ -67,6 +76,14 @@
     public ClassMapping getCandidate() {
         return _candidate;
     }
+    
+    public boolean getSubs() {
+        return _subs;
+    }
+    
+    public String getSubqAlias() {
+        return _subqAlias;
+    }
 
     public Class getType() {
         if (_exps != null && _type == null) {
@@ -93,16 +110,19 @@
     }
 
     public String getCandidateAlias() {
-        return _alias;
+        return _subqAlias;
     }
 
     public void setQueryExpressions(QueryExpressions query) {
         _exps = query;
+        _select.setContext(query.ctx());
     }
 
     public ExpState initialize(Select sel, ExpContext ctx, int flags) {
-        if (_exps.projections.length == 1)
-            return ((Val) _exps.projections[0]).initialize(sel, ctx, flags);
+        _select.setParent(sel, null);
+        if (_exps.projections.length == 1) {
+            return ((Val) _exps.projections[0]).initialize(_select, ctx, flags);
+        }
         return ExpState.NULL;
     }
 
@@ -180,7 +200,7 @@
     private void appendTo(Select sel, ExpContext ctx, ExpState state, 
         SQLBuffer sql, int index, boolean size) {
         QueryExpressionsState substate = new QueryExpressionsState();
-        Select sub = _cons.evaluate(ctx, sel, _alias, _exps, substate);
+        Select sub = _cons.evaluate(ctx, sel, _subqAlias, _exps, substate);
         _cons.select(sub, ctx, _candidate, _subs, _exps, substate, 
             JDBCFetchConfiguration.EAGER_NONE);
 

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java Mon Jul 20 17:49:36 2009
@@ -583,6 +583,7 @@
             _unq = _info.getJoinUnique(this, false, adapt);
             _joinTableUniques = _info.getJoinTableUniques(this, false, adapt);
             _idx = _info.getJoinIndex(this, adapt);
+            table.setAssociation();
         }
     }
 

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Table.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Table.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Table.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Table.java Mon Jul 20 17:49:36 2009
@@ -62,7 +62,8 @@
     private Unique[] _unqs = null;
     private String _comment = null;
     private int _lineNum = 0;  
-    private int _colNum = 0;  
+    private int _colNum = 0;
+    private boolean _isAssociation = false;
 
     /**
      * Default constructor.
@@ -84,6 +85,14 @@
         _schema = schema;
     }
 
+    public void setAssociation() {
+        _isAssociation = true;
+    }
+
+    public boolean isAssociation() {
+        return _isAssociation;
+    }
+
     /**
      * Called when the table is removed from its schema. Removes all table
      * members, and invalidates the table.

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java Mon Jul 20 17:49:36 2009
@@ -47,6 +47,7 @@
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.schema.ForeignKey;
 import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.lib.util.Closeable;
 import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.util.UnsupportedException;
@@ -885,7 +886,22 @@
             return this;
         }
 
+        public Joins setJoinContext(Context context) {
+            return this;
+        }
+
         public void appendTo(SQLBuffer buf) {
         }
+
+        public Joins setCorrelatedVariable(String var) {
+            return this;
+        }
+
+        public String getCorrelatedVariable() {
+            return null;
+        }
+        
+        public void moveJoinsToParent() {
+        }
     }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Mon Jul 20 17:49:36 2009
@@ -2197,14 +2197,59 @@
             Iterator itr = sel.getJoinIterator();
             boolean first = true;
             while (itr.hasNext()) {
-                fromSQL.append(toSQL92Join((Join) itr.next(), forUpdate,
+                Join join = (Join) itr.next();
+                if (correlatedJoinCondition(join, sel))
+                    continue;
+                fromSQL.append(toSQL92Join(sel, join, forUpdate,
                     first));
                 first = false;
+                if (itr.hasNext() && join.isCorrelated()) {
+                    fromSQL.append(", ");
+                    first = true;
+                }
+            }
+
+            for (Iterator itr2 = aliases.iterator(); itr2.hasNext();) {
+                String tableAlias = itr2.next().toString();
+                if (fromSQL.getSQL().indexOf(tableAlias) == -1) {
+                    if (!first)
+                        fromSQL.append(", ");
+                    fromSQL.append(tableAlias);
+                    first = false;
+                }
             }
         }
         return fromSQL;
     }
 
+    private boolean correlatedJoinCondition(Join join, Select sel) {
+        if (!join.isCorrelated())
+            return false;
+        Iterator itr = sel.getJoinIterator();
+        boolean skip = false;
+        //if table1 in join is in the main query, table2 is in
+        //subquery, and table2 participates in other joins
+        //in subquery, the join condition can only be placed in 
+        //the where clause in the subquery
+        while (itr.hasNext()) {
+            Join join1 = (Join) itr.next();
+            if (join == join1)
+                continue;
+            if (join.getIndex2() == join1.getIndex1() ||
+                join.getIndex2() == join1.getIndex2()) {
+                skip = true;
+                if (join.getForeignKey() != null){
+                    SQLBuffer where = new SQLBuffer(this);
+                    where.append("(").append(toTraditionalJoin(join)).append(")");
+                    sel.where(where.getSQL());
+                }                
+                break;
+            }
+        }
+        return skip;
+    }
+    
+    
     /**
      * Return the FROM clause for a select that selects from a tmp table
      * created by an inner select.
@@ -2308,9 +2353,11 @@
      * Use the given join instance to create SQL joining its tables in
      * the SQL92 style.
      */
-    public SQLBuffer toSQL92Join(Join join, boolean forUpdate, boolean first) {
+    public SQLBuffer toSQL92Join(Select sel, Join join, boolean forUpdate,
+        boolean first) {
         SQLBuffer buf = new SQLBuffer(this);
-        if (first) {
+        boolean corelated = join.isCorrelated();
+        if (first && !corelated) {
             buf.append(join.getTable1()).append(" ").
                 append(join.getAlias1());
             if (forUpdate && tableForUpdateClause != null)
@@ -2318,23 +2365,31 @@
         }
 
         buf.append(" ");
-        if (join.getType() == Join.TYPE_OUTER)
-            buf.append(outerJoinClause);
-        else if (join.getType() == Join.TYPE_INNER)
-            buf.append(innerJoinClause);
-        else // cross
-            buf.append(crossJoinClause);
-        buf.append(" ");
+        if (!corelated) {
+            if (join.getType() == Join.TYPE_OUTER)
+                buf.append(outerJoinClause);
+            else if (join.getType() == Join.TYPE_INNER)
+                buf.append(innerJoinClause);
+            else // cross
+                buf.append(crossJoinClause);
+            buf.append(" ");
+        }
 
         buf.append(join.getTable2()).append(" ").append(join.getAlias2());
         if (forUpdate && tableForUpdateClause != null)
             buf.append(" ").append(tableForUpdateClause);
 
-        if (join.getForeignKey() != null)
-            buf.append(" ON ").append(toTraditionalJoin(join));
-        else if (requiresConditionForCrossJoin &&
-            join.getType() == Join.TYPE_CROSS)
-            buf.append(" ON (1 = 1)");
+        if (!corelated) {
+            if (join.getForeignKey() != null)
+                buf.append(" ON ").append(toTraditionalJoin(join));
+            else if (requiresConditionForCrossJoin &&
+                    join.getType() == Join.TYPE_CROSS)
+                buf.append(" ON (1 = 1)");
+        } else if (join.getForeignKey() != null){
+            SQLBuffer where = new SQLBuffer(this);
+            where.append("(").append(toTraditionalJoin(join)).append(")");
+            sel.where(where.getSQL());
+        }
 
         return buf;
     }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Join.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Join.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Join.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Join.java Mon Jul 20 17:49:36 2009
@@ -45,6 +45,8 @@
     private int _subs;
     private Joins _joins;
     private boolean _inverse;
+    private boolean _correlated = false;
+    private boolean _isNotMyJoin = false;
 
     /**
      * Constructor for inner and outer joins.
@@ -189,5 +191,21 @@
             return null;
         }
     }
+
+    public boolean isCorrelated() {
+        return _correlated;
+    }
+
+    public void setCorrelated() {
+        _correlated = true;
+    }
+
+    public boolean isNotMyJoin() {
+        return _isNotMyJoin;
+    }
+
+    public void setIsNotMyJoin() {
+        _isNotMyJoin = true;
+    }
 }
 

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java Mon Jul 20 17:49:36 2009
@@ -21,6 +21,7 @@
 import org.apache.openjpa.jdbc.meta.ClassMapping;
 import org.apache.openjpa.jdbc.schema.ForeignKey;
 import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.kernel.exps.Context;
 
 /**
  * Tracks joins made when traversing relations in a select.
@@ -77,4 +78,28 @@
      * Set the subquery alias.
      */
     public Joins setSubselect(String alias);
+
+    /**
+     * Set subquery context when traversing into the next join is
+     * in transition from parent context to subquery.
+     * @param context
+     */
+    public Joins setJoinContext(Context context);
+    
+    /**
+     * Set the correlated variable name being traversed into
+     * with the next join.
+     */
+    public Joins setCorrelatedVariable(String var);
+
+    /**
+     * Return correlated variable name
+     * @return
+     */
+    public String getCorrelatedVariable();
+
+    /**
+     * Move joins that belong to subquery's parent
+     */
+    public void moveJoinsToParent();
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java Mon Jul 20 17:49:36 2009
@@ -30,6 +30,7 @@
 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
 import org.apache.openjpa.jdbc.kernel.JDBCStore;
 import org.apache.openjpa.kernel.exps.Value;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.jdbc.meta.ClassMapping;
 import org.apache.openjpa.jdbc.meta.FieldMapping;
 import org.apache.openjpa.jdbc.schema.Column;
@@ -880,6 +881,18 @@
             boolean force) {
             sel.setExpectedResultCount(expectedResultCount, force);
         }
+
+        public void setContext(Context context) {
+            sel.setContext(context);
+        }
+
+        public Context ctx() {
+            return sel.ctx();
+        }
+
+        public void setSchemaAlias(String schemaAlias) {
+            sel.setSchemaAlias(schemaAlias);
+        }
     }
 
     /**

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java Mon Jul 20 17:49:36 2009
@@ -30,6 +30,7 @@
 import org.apache.openjpa.jdbc.schema.ForeignKey;
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.kernel.exps.Value;
+import org.apache.openjpa.kernel.exps.Context;
 
 /**
  * Abstraction of a SQL SELECT statement.
@@ -701,4 +702,21 @@
      * Return the alias for the given column, without creating new table alias
      */
     public String getColumnAlias(Column col, Object path);
+
+    /**
+     * Set JPQL query context for this select
+     * @param context
+     */
+    public void setContext(Context context);
+
+    /**
+     * Return the JPQL query context of this select
+     */
+    public Context ctx();
+
+    /**
+     * Record the initial schemaAlias of a join path
+     * @param schemaAlias
+     */
+    public void setSchemaAlias(String schemaAlias);
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java Mon Jul 20 17:49:36 2009
@@ -26,7 +26,6 @@
 import java.sql.Types;
 import java.util.AbstractList;
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -56,6 +55,7 @@
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.kernel.StoreContext;
 import org.apache.openjpa.kernel.exps.Value;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.util.ApplicationIds;
@@ -119,9 +119,6 @@
     // 'parent.address.street' for the purposes of comparisons
     private Map _aliases = null;
 
-    // to cache table alias using Table as the key
-    private Map _tableAliases = null;
-
     // map of indexes to table aliases like 'TABLENAME t0'
     private SortedMap _tables = null;
 
@@ -165,13 +162,12 @@
     // from select if this select selects from a tmp table created by another
     private SelectImpl _from = null;
     protected SelectImpl _outer = null;
-    
-    // bitSet indicating if an alias is removed from parent select
-    // bit 0 : correspond to alias 0
-    // bit 1 : correspond to alias 1, etc.
-    // if the bit is set, the corresponding alias has been removed from parent
-    // and recorded under subselect.
-    private BitSet _removedAliasFromParent = new BitSet(16);
+
+    // JPQL Query context this select is associated with
+    private Context _ctx = null;
+
+    // A path navigation is begin with this schema alias
+    private String _schemaAlias = null;
      
     /**
      * Helper method to return the proper table alias for the given alias index.
@@ -206,6 +202,21 @@
         _selects._dict = _dict;
     }
 
+    public void setContext(Context context) {
+        if (_ctx == null) {
+            _ctx = context;
+            _ctx.setSelect(this);
+        }
+    }
+
+    public Context ctx() {
+        return _ctx;
+    }
+
+    public void setSchemaAlias(String schemaAlias) {
+        _schemaAlias = schemaAlias;
+    }
+
     /////////////////////////////////
     // SelectExecutor implementation
     /////////////////////////////////
@@ -521,7 +532,7 @@
 
     public void setParent(Select parent, String path) {
         if (path != null)
-            _subPath = path + ':';
+            _subPath = path;
         else
             _subPath = null;
 
@@ -546,62 +557,6 @@
             else
                 _joinSyntax = _parent._joinSyntax;
         }
-        
-        if (_parent.getAliases() == null || _subPath == null)
-            return;
-
-        if (_parent._aliases.size() <= 1)
-            return;
-        // Do not remove aliases for databases that use SYNTAX_DATABASE (oracle)
-        if(_parent._joinSyntax != JoinSyntaxes.SYNTAX_DATABASE) {
-            // resolve aliases for subselect from parent
-            Set<Map.Entry> entries = _parent.getAliases().entrySet();
-            for (Map.Entry entry : entries) {
-                Object key = entry.getKey();
-                Integer alias = (Integer) entry.getValue();
-                if (key.toString().indexOf(_subPath) != -1 ||
-                    _parent.findTableAlias(alias) == false) {
-                    if (_aliases == null)
-                        _aliases = new HashMap();
-                    _aliases.put(key, alias);
-    
-                    Object tableString = _parent.getTables().get(alias);
-                    if (_tables == null)
-                        _tables = new TreeMap();
-                    _tables.put(alias, tableString);
-                    
-                    _removedAliasFromParent.set(alias.intValue());
-                }
-            }
-            
-            if (_aliases != null) {
-                // aliases moved into subselect should be removed from parent
-                entries = _aliases.entrySet();
-                for (Map.Entry entry : entries) {
-                    Object key = entry.getKey();
-                    Integer alias = (Integer) entry.getValue();
-                    if (key.toString().indexOf(_subPath) != -1 ||
-                        _parent.findTableAlias(alias) == false) {
-                        _parent.removeAlias(key);
-    
-                        Object tableString = _parent.getTables().get(alias);
-                        _parent.removeTable(alias);
-                    }
-                }
-            }
-        }
-    }
-    
-    private boolean findTableAlias(Integer alias) {
-        // if alias is defined and referenced, return true.
-        String value = "t" + alias.toString() + ".";
-        if (_tableAliases != null)
-            if (_tableAliases.containsValue(value))
-               return _tables.containsKey(alias);
-           else
-               return _joins != null;
-        else
-            return true;
     }
     
     public Map getAliases() {
@@ -773,17 +728,6 @@
      * Return the alias for the given column.
      */
     private String getColumnAlias(String col, Table table, PathJoins pj) {
-        String tableAlias = null;
-        if (pj == null || pj.path() == null) {
-            if (_tableAliases == null)
-                _tableAliases = new HashMap();
-            tableAlias = (String) _tableAliases.get(table);
-            if (tableAlias == null) {
-                tableAlias = getTableAlias(table, pj).toString();
-                _tableAliases.put(table, tableAlias);
-            }
-            return new StringBuilder(tableAlias).append(col).toString();
-        }
         return getTableAlias(table, pj).append(col).toString();
     }
     
@@ -1663,10 +1607,7 @@
             if ((_flags & OUTER) != 0)
                 pj = (PathJoins) outer(pj);
             if (record) {
-                if (!pj.isEmpty())
-                    removeParentJoins(pj);
                 if (!pj.isEmpty()) {
-                    removeJoinsFromSubselects(pj);
                     if (_joins == null)
                         _joins = new SelectJoins(this);
                     if (_joins.joins() == null)
@@ -1679,43 +1620,6 @@
         return pj;
     }
 
-    /**
-     * Remove any joins already in our parent select from the given non-empty
-     * join set.
-     */
-    private void removeParentJoins(PathJoins pj) {
-        if (_parent == null)
-            return;
-        if (_parent._joins != null && !_parent._joins.isEmpty()) {
-            boolean removed = false;
-            if (!_removedAliasFromParent.isEmpty()) {
-                for (Iterator itr = pj.joins().iterator(); itr.hasNext();) {
-                   Join jn = (Join) itr.next();
-                   if (_aliases.containsValue(jn.getIndex1()))
-                       removed = _parent._joins.joins().remove(jn);
-                }
-            }
-            if (!removed)
-                pj.joins().removeAll(_parent._joins.joins());
-        }
-        if (!pj.isEmpty())
-            _parent.removeParentJoins(pj);
-    }
-
-    /**
-     * Remove the given non-empty joins from the joins of our subselects.
-     */
-    private void removeJoinsFromSubselects(PathJoins pj) {
-        if (_subsels == null)
-            return;
-        SelectImpl sub;
-        for (int i = 0; i < _subsels.size(); i++) {
-            sub = (SelectImpl) _subsels.get(i);
-            if (sub._joins != null && !sub._joins.isEmpty())
-                sub._joins.joins().removeAll(pj.joins());
-        }
-    }
-
     public SelectExecutor whereClone(int sels) {
         if (sels < 1)
             sels = 1;
@@ -1732,6 +1636,7 @@
             sel._flags &= ~EAGER_TO_MANY;
             sel._flags &= ~FORCE_COUNT;
             sel._joinSyntax = _joinSyntax;
+            sel._schemaAlias = _schemaAlias;
             if (_aliases != null)
                 sel._aliases = new HashMap(_aliases);
             if (_tables != null)
@@ -1888,6 +1793,8 @@
     public void append(SQLBuffer buf, Joins joins) {
         if (joins == null || joins.isEmpty())
             return;
+        if (_joinSyntax == JoinSyntaxes.SYNTAX_SQL92)
+            return;
 
         if (!buf.isEmpty())
             buf.append(" AND ");
@@ -1915,6 +1822,10 @@
         return and((PathJoins) joins1, (PathJoins) joins2, true);
     }
 
+    public Select getSelect() {
+        return null;
+    }
+
     /**
      * Combine the given joins.
      */
@@ -1925,20 +1836,25 @@
 
         SelectJoins sj = new SelectJoins(this);
         if (j1 == null || j1.isEmpty()) {
-            if (nullJoins)
-                sj.setJoins(j2.joins());
-            else
-                sj.setJoins(new JoinSet(j2.joins()));
+            if (j2.getSelect() == this) {
+                if (nullJoins)
+                    sj.setJoins(j2.joins());
+                else
+                    sj.setJoins(new JoinSet(j2.joins()));
+            }
         } else {
-            JoinSet set;
-            if (nullJoins)
-                set = j1.joins();
-            else
-                set = new JoinSet(j1.joins());
+            JoinSet set = null;
+            if (j1.getSelect() == this) {
+                if (nullJoins)
+                    set = j1.joins();
+                else
+                    set = new JoinSet(j1.joins());
 
-            if (j2 != null && !j2.isEmpty())
-                set.addAll(j2.joins());
-            sj.setJoins(set);
+                if (j2 != null && !j2.isEmpty()
+                    && j2.getSelect() == this)
+                    set.addAll(j2.joins());
+                sj.setJoins(set);
+            }
         }
 
         // null previous joins; all are combined into this one
@@ -2070,72 +1986,111 @@
         if (_from != null)
             return -1;
 
+        Integer i = null;
         Object key = table.getFullName();
         if (pj != null && pj.path() != null)
             key = new Key(pj.path().toString(), key);
 
+        if (_ctx != null)
+            i = findAliasForQuery(table, pj, key, create);
+
+        if (i != null)
+            return i.intValue();
+
         // check out existing aliases
-        Integer i = findAlias(table, key, false, null);
+        i = findAlias(table, key);
+
         if (i != null)
             return i.intValue();
         if (!create)
             return -1;
 
         // not found; create alias
-        i = Numbers.valueOf(aliasSize());
+        i = Numbers.valueOf(aliasSize(null));
+//        System.out.println("GetTableIndex\t"+
+//                ((_parent != null) ? "Sub" :"") +
+//                " created alias: "+
+//                i.intValue()+ " "+ key);
         recordTableAlias(table, key, i);
         return i.intValue();
     }
 
-    /**
-     * Attempt to find the alias for the given key.
-     *
-     * @param fromParent whether a parent is checking its subselects
-     * @param fromSub the subselect checking its parent
-     */
-    private Integer findAlias(Table table, Object key, boolean fromParent,
-        SelectImpl fromSub) {
+    private Integer findAliasForQuery(Table table, PathJoins pj, Object key,
+        boolean create) {
+        Integer i = null;
+        SelectImpl sel = this;
+        String alias = _schemaAlias;
+        if (isPathInThisContext(pj) || table.isAssociation())          
+            alias = null;
+
+        // find the context where this alias is defined
+        Context ctx = (alias != null) ?
+            _ctx.findContext(alias) : null;
+        if (ctx != null)
+            sel = (SelectImpl) ctx.getSelect();
+
+        if (!create) 
+            i = sel.findAlias(table, key);  // find in parent and in myself
+        else
+            i = sel.getAlias(table, key); // find in myself
+        if (i != null)
+            return i;
+        
+        if (create) { // create here
+            i = sel.createAlias(table, key);
+        } else if (ctx != null && ctx != ctx()) { // create in other select
+            i = ((SelectImpl)ctx.getSelect()).createAlias(table, key);
+        }
+
+        return i;
+    }
+
+    private boolean isPathInThisContext(PathJoins pj) {
+        // currCtx is set from Action, it is reset to null after the PCPath initialization
+        Context currCtx = pj == null ? null : ((PathJoinsImpl)pj).context;
+        
+        // lastCtx is set to currCtx after the SelectJoins.join. pj.lastCtx and pj.path string are 
+        // the last snapshot of pj. They will be used together for later table alias resolution in
+        // the getColumnAlias(). 
+        Context lastCtx = pj == null ? null : ((PathJoinsImpl)pj).lastContext;
+        Context thisCtx = currCtx == null ? lastCtx : currCtx;
+        String corrVar = pj == null ? null : pj.getCorrelatedVariable();
+        
+        return (pj != null && pj.path() != null && 
+            (corrVar == null || (thisCtx != null && ctx() == thisCtx)));
+    }
+ 
+    private Integer getAlias(Table table, Object key) {
+        Integer alias = null;
+        if (_aliases != null)
+            alias = (Integer) _aliases.get(key);
+        return alias;
+    }
+
+    private int createAlias(Table table, Object key) {
+        Integer i = Numbers.valueOf(ctx().nextAlias());
+//        System.out.println("\t"+
+//                ((_parent != null) ? "Sub" :"") +
+//                "Query created alias: "+ 
+//                i.intValue()+ " "+ key);
+        recordTableAlias(table, key, i);
+        return i.intValue();
+    }
+
+    private Integer findAlias(Table table, Object key) {
         Integer alias = null;
         if (_aliases != null) {
-            alias = (Integer) ((fromParent) ? _aliases.remove(key)
-                : _aliases.get(key));
+            alias = (Integer) _aliases.get(key);
             if (alias != null) {
-                if (fromParent)
-                    _tables.remove(alias);
                 return alias;
             }
         }
-        if (!fromParent && _parent != null) {
-            boolean removeAliasFromParent = key.toString().indexOf(":") != -1;
-            alias = _parent.findAlias(table, key, removeAliasFromParent, this);
+        if (_parent != null) {
+            alias = _parent.findAlias(table, key);
             if (alias != null) {
-                if (removeAliasFromParent) {
-                    recordTableAlias(table, key, alias);
-                    _removedAliasFromParent.set(alias.intValue());
-                }
                 return alias;
             }
         }
-        if (_subsels != null) {
-            SelectImpl sub;
-            for (int i = 0; i < _subsels.size(); i++) {
-                sub = (SelectImpl) _subsels.get(i);
-                if (sub == fromSub)
-                    continue;
-                if (alias != null) {
-                    if (sub._aliases != null)
-                        sub._aliases.remove(key);
-                    if (sub._tables != null)
-                        sub._tables.remove(alias);
-                } else {
-                    if (key instanceof String) {
-                        alias = sub.findAlias(table, key, true, null);
-                        if (!fromParent && alias != null)
-                            recordTableAlias(table, key, alias);
-                    }
-                }
-            }
-        }
         return alias;
     }
 
@@ -2157,26 +2112,16 @@
     /**
      * Calculate total number of aliases.
      */
-    private int aliasSize() {
-        return aliasSize(false, null);
-    }
-
-    /**
-     * Calculate total number of aliases.
-     *
-     * @param fromParent whether a parent is checking its subselects
-     * @param fromSub the subselect checking its parent
-     */
-    private int aliasSize(boolean fromParent, SelectImpl fromSub) {
-        int aliases = (fromParent || _parent == null) ? 0
-            : _parent.aliasSize(false, this);
+    private int aliasSize(SelectImpl fromSub) {
+        int aliases = (_parent == null) ? 0
+            : _parent.aliasSize(this);
         aliases += (_aliases == null) ? 0 : _aliases.size();
         if (_subsels != null) {
             SelectImpl sub;
             for (int i = 0; i < _subsels.size(); i++) {
                 sub = (SelectImpl) _subsels.get(i);
                 if (sub != fromSub)
-                    aliases += sub.aliasSize(true, null);
+                    aliases += sub.aliasSize(null);
             }
         }
         return aliases;
@@ -2268,6 +2213,37 @@
      */
     private static class Placeholder {
     }
+    
+    public void reset() {
+        _aliases = null;
+        _eager = null;
+        _eagerKeys = null;
+        _expectedResultCount = 0;
+        _flags = 0;
+        _from = null;
+        _grouped = null;
+        _grouping = null;
+        _having = null;
+        _joins = null;
+        _joinSyntax = 0;
+        _nullIds = 0;
+        _ordered = null;
+        _ordering = null;
+        _orders = 0;
+        _outer = null;
+        _parent = null;
+        _placeholders = 0;
+        _preJoins = null;
+        _schemaAlias = null;
+        _selects._aliases = null;
+        _selects._ids = null;
+        _subPath = null;
+        _subsels = null;
+        _tables = null;
+        _where = null;
+        
+    }
+    
 
     /**
      * Key type used for aliases.
@@ -2599,6 +2575,21 @@
                 return this;
             return new PathJoinsImpl().setSubselect(alias);
         }
+
+        public Joins setCorrelatedVariable(String var) {
+            return this;
+        }
+
+        public Joins setJoinContext(Context ctx) {
+            return this;
+        }
+
+        public String getCorrelatedVariable() {
+            return null;
+        }
+
+        public void moveJoinsToParent() {
+        }
     }
 
     /**
@@ -2609,6 +2600,13 @@
 
         protected StringBuffer path = null;
         protected String var = null;
+        protected String correlatedVar = null;
+        protected Context context = null;
+        protected Context lastContext = null;
+
+        public Select getSelect() {
+            return null;
+        }
 
         public boolean isOuter() {
             return false;
@@ -2642,9 +2640,25 @@
             return this;
         }
 
+        public String getVariable() {
+            return var;
+        }
+        
+        public Joins setCorrelatedVariable(String var) {
+            this.correlatedVar = var;
+            return this;
+        }
+        
+        public String getCorrelatedVariable() {
+            return correlatedVar;
+        }
+
+        public Joins setJoinContext(Context context) {
+            this.context = context;
+            return this;
+         }
+
         public Joins setSubselect(String alias) {
-            if (!alias.endsWith(":"))
-                alias += ':';
             append(alias);
             return this;
         }
@@ -2700,6 +2714,9 @@
             return "PathJoinsImpl<" + hashCode() + ">: "
                 + String.valueOf(path);
         }
+
+        public void moveJoinsToParent() {
+        }
     }
 
     /**
@@ -2718,6 +2735,10 @@
             _sel = sel;
         }
 
+        public Select getSelect() {
+            return _sel;
+        }
+
         public boolean isOuter() {
             return _outer;
         }
@@ -2778,9 +2799,14 @@
             // until we get past the local table
             String var = this.var;
             this.var = null;
+            Context ctx = context; 
+            context = null; 
 
             int alias1 = _sel.getTableIndex(localTable, this, true);
             this.append(var);
+            this.append(correlatedVar);
+            context = ctx; 
+            
             int alias2 = _sel.getTableIndex(foreignTable, this, true);
             Join j = new Join(localTable, alias1, foreignTable, alias2,
                 null, false);
@@ -2789,7 +2815,10 @@
             if (_joins == null)
                 _joins = new JoinSet();
             _joins.add(j);
+            setCorrelated(j);
             _outer = false;
+            lastContext =  context;
+            context = null;
             return this;
         }
 
@@ -2817,6 +2846,8 @@
             // until we get past the local table
             String var = this.var;
             this.var = null;
+            Context ctx = context; 
+            context = null; 
 
             // get first table alias before updating path; if there is a from
             // select then we shouldn't actually create a join object, since
@@ -2825,13 +2856,19 @@
             Table table1 = null;
             int alias1 = -1;
             if (createJoin) {
+                boolean createIndex = true;
                 table1 = (inverse) ? fk.getPrimaryKeyTable() : fk.getTable();
-                alias1 = _sel.getTableIndex(table1, this, true);
+                if (correlatedVar != null)
+                    createIndex = false;  // not to create here
+                alias1 = _sel.getTableIndex(table1, this, createIndex);
             }
 
             // update the path with the relation name before getting pk alias
             this.append(name);
             this.append(var);
+            this.append(correlatedVar);
+            context = ctx; 
+            
             if (toMany) {
                 _sel._flags |= IMPLICIT_DISTINCT;
                 _sel._flags |= TO_MANY;
@@ -2839,9 +2876,16 @@
             _outer = outer;
 
             if (createJoin) {
+                boolean createIndex = true;
                 Table table2 = (inverse) ? fk.getTable() 
                     : fk.getPrimaryKeyTable();
-                int alias2 = _sel.getTableIndex(table2, this, true);
+                if (table2.isAssociation())
+                    createIndex = true;
+                else if (context == _sel.ctx()) 
+                   createIndex = true;
+                else if (correlatedVar != null)
+                    createIndex = false;
+                int alias2 = _sel.getTableIndex(table2, this, createIndex);
                 Join j = new Join(table1, alias1, table2, alias2, fk, inverse);
                 j.setType((outer) ? Join.TYPE_OUTER : Join.TYPE_INNER);
 
@@ -2850,10 +2894,91 @@
                 if (_joins.add(j) && (subs == Select.SUBS_JOINABLE 
                     || subs == Select.SUBS_NONE))
                     j.setRelation(target, subs, clone(_sel));
+
+                setCorrelated(j);
             }
+            lastContext = context;
+            context = null;
             return this;
         }
 
+        private void setCorrelated(Join j) {
+            if (_sel._parent == null)
+                return;
+
+            if (_sel._aliases == null) {
+                j.setIsNotMyJoin();
+               return;
+            }
+
+            Object aliases[] = _sel._aliases.values().toArray();
+            boolean found1 = false;
+            boolean found2 = false;
+
+            for (int i = 0; i < aliases.length; i++) {
+                int alias = ((Integer)aliases[i]).intValue();
+                if (alias == j.getIndex1())
+                    found1 = true;
+                if (alias == j.getIndex2())
+                    found2 = true;
+            }
+                
+            if (found1 && found2)
+                return;
+            else if (!found1 && !found2) {
+                j.setIsNotMyJoin();
+                return;
+            }
+            else {
+                j.setCorrelated();
+            }
+        }
+
+        public void moveJoinsToParent() {
+            if (_joins == null)
+                return;
+           Join j = null;
+           List<Join> removed = new ArrayList<Join>(5);
+           for (Iterator itr = _joins.iterator(); itr.hasNext();) {
+               j = (Join) itr.next();
+               if (j.isNotMyJoin()) {
+                   addJoinsToParent(_sel._parent, j);
+                   removed.add(j);
+               }
+           }
+           for (Join join : removed) {
+               _joins.remove(join);
+           }
+        }
+
+        private void addJoinsToParent(SelectImpl parent, Join join) {
+            if (parent._aliases == null)
+                return;
+            Object aliases[] = parent._aliases.values().toArray();
+            boolean found1 = false;
+            boolean found2 = false;
+
+            for (int i = 0; i < aliases.length; i++) {
+                int alias = ((Integer)aliases[i]).intValue();
+                if (alias == join.getIndex1())
+                    found1 = true;
+                if (alias == join.getIndex2())
+                    found2 = true;
+            }
+                
+            if (found1 && found2) {
+                // this is my join, add join
+                if (parent._joins == null) 
+                    parent._joins = new SelectJoins(parent);
+                SelectJoins p = parent._joins;
+                if (p.joins() == null)
+                    p.setJoins(new JoinSet());                
+                p.joins().add(join);
+            }
+            else if (parent._parent != null)
+                addJoinsToParent(parent._parent, join);
+        }
+
         public SelectJoins clone(SelectImpl sel) {
             SelectJoins sj = new SelectJoins(sel);
             sj.var = var;
@@ -3067,6 +3192,25 @@
             _idents = null;
         }
     }
+
+    public Joins setCorrelatedVariable(String var) {
+        if (var == null)
+            return this;
+        return new SelectJoins(this).setCorrelatedVariable(var);
+    }
+    
+    public Joins setJoinContext(Context ctx) {
+        if (ctx == null)
+            return this;
+        return new SelectJoins(this).setJoinContext(ctx);
+    }
+
+    public String getCorrelatedVariable() {
+        return null;
+    }
+
+    public void moveJoinsToParent() {
+    }
 }
 
 /**
@@ -3106,5 +3250,11 @@
      * Null the set of {@link Join} elements.
      */
     public void nullJoins();
+
+    /**
+     * The select owner of this join
+     * @return
+     */
+    public Select getSelect();
 }
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java Mon Jul 20 17:49:36 2009
@@ -169,10 +169,12 @@
             type = TYPE_OBJECT;
         else
             meta = getMetaData(type, false);
-        if (meta != null)
+        if (meta != null) {
             addAccessPath(meta);
+            addSchemaToContext(id, meta);
+        }
 
-        Value var;
+        Value var = null;
         if (bind)
             var = factory.newBoundVariable(id, type);
         else
@@ -182,6 +184,8 @@
         if (_seenVars == null)
             _seenVars = new HashMap<String,Value>();
         _seenVars.put(id, var);
+
+        addVariableToContext(id, var);
         return var;
     }
 
@@ -308,7 +312,7 @@
             }
         }
 
-        if (meta != null || !pcOnly)
+        if (meta != null || !pcOnly) 
             path.get(fmd, allowNull);
 
         return path;
@@ -521,5 +525,28 @@
      * Returns the current string being parsed; used for error messages.
 	 */
 	protected abstract String currentQuery ();
+
+    /**
+     * Register the schema alias to the current JPQL query context.
+     * @param alias
+     * @param meta
+     */
+    protected abstract void addSchemaToContext(String alias,
+        ClassMetaData meta);
+
+    /**
+     * Register the variable associated with the schema alias (id) to
+     * the current JPQL query context.
+     * @param id
+     * @param var
+     */
+    protected abstract void addVariableToContext(String id, Value var);
+
+    /**
+     * Returns the variable associated with the schema alias (id).
+     * @param id
+     * @return
+     */
+    protected abstract Value getSeenVariable(String id);
 }
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java Mon Jul 20 17:49:36 2009
@@ -196,4 +196,14 @@
     public XMLMetaData getXmlMapping() {
         return null;
     }
+
+    public void setSchemaAlias(String schemaAlias) {
+    }
+
+    public String getSchemaAlias() {
+        return null;
+    }
+    
+    public void setSubqueryContext(Context conext) {
+    }
 }

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java?rev=795934&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java Mon Jul 20 17:49:36 2009
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.kernel.exps;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.ParsedJPQL;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * JPQL / Criteria Query Context
+ * @since 2.0
+ *
+ */
+public class Context implements Serializable {
+
+    public final ParsedJPQL parsed;
+    public ClassMetaData meta;
+    public String schemaAlias;
+    public Subquery subquery;
+    public Expression from = null;
+    private Context parent = null;
+    private List<Context> subsels = null;
+    private Object select = null;
+    private int aliasCount = -1; 
+    private Map<String,Value> variables = new HashMap<String,Value>();
+    private Map<String,ClassMetaData> schemas =
+        new HashMap<String,ClassMetaData>();
+
+    public Context(ParsedJPQL parsed, Subquery subquery, Context parent) {
+        this.parsed = parsed;
+        this.subquery = subquery;
+        this.parent = parent;
+        if (subquery != null) {
+            this.select = subquery.getSelect();
+            parent.addSubselContext(this);
+        }
+    }
+
+    public void setSubquery(Subquery subquery) {
+        this.subquery = subquery;
+        this.select = subquery.getSelect();
+        parent.addSubselContext(this);
+    }
+    
+    public ClassMetaData meta() {
+        return meta;
+    }
+
+    public String schemaAlias() {
+        return schemaAlias;
+    }
+
+    public Subquery subquery() {
+        return subquery;
+    }
+
+    /**
+     * Returns next table alias to be created.
+     * @return
+     */
+    public int nextAlias() {
+        Context p = this;
+        while (p.subquery != null) {
+            p = p.parent;
+        }
+        p.aliasCount++;
+        return p.aliasCount;
+    }
+
+    /**
+     * Reset alias count for prepared query cache
+     *
+     */
+    public void resetAliasCount() {
+        Context p = this;
+        while (p.subquery != null) {
+            p = p.parent;
+        }
+        p.aliasCount = -1;
+    }
+
+    /**
+     * Register the select for this context.
+     * @param select
+     */
+    public void setSelect(Object select) {
+        this.select = select;
+    }
+
+    /**
+     * Returns the select associated with this context.
+     * @return
+     */
+    public Object getSelect() {
+        return select;
+    }
+
+    /**
+     * Register the subquery context in this context.
+     * @param sub
+     */
+    private void addSubselContext(Context sub) {
+        if (subsels == null)
+            subsels = new ArrayList<Context>();
+        subsels.add(sub);
+    }
+
+    /**
+     * Returns the subquery context.
+     * @return
+     */
+    public List<Context> getSubselContexts() {
+        return subsels;
+    }
+
+    /**
+     * Returns the subquery in this context.
+     * @return
+     */
+    public Subquery getSubquery() {
+        return subquery;
+    }
+
+    public Context getParent() {
+        return parent;
+    }
+
+    public void setParent(Context parent) {
+        this.parent = parent;
+    }
+
+    public void addVariable(String id, Value var) {
+        variables.put(id.toLowerCase(), var);
+    }
+
+    public void addSchema(String id, ClassMetaData meta) {
+        schemas.put(id.toLowerCase(), meta);
+    }
+
+    public ClassMetaData getSchema(String id) {
+        if (id != null)
+            return schemas.get(id.toLowerCase());
+        return null;
+    }
+
+    /**
+     * Given an alias and return its associated variable.
+     * @param var
+     * @return
+     */
+    public Value getVariable(String var) {
+        Value variable = var == null ? null 
+            : variables.get(var.toLowerCase());
+        return variable;
+    }
+
+    /**
+     * Given an alias find the context of its associated
+     * variable where it is defined.
+     * @param alias
+     * @return
+     */
+    public Context findContext(String alias) {
+        Value var = getVariable(alias);
+        if (var != null)
+            return this;
+        for (Context p = parent; p != null; ) {
+            var = p.getVariable(alias);
+            if (var != null)
+                return p;
+            p = p.parent;
+        }
+        if (subsels != null) {
+            for (Context subsel : subsels) {
+                if (subsel != null) {
+                    var = subsel.getVariable(alias);
+                    if (var != null)
+                        return subsel;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Given an alias find the variable in JPQL contexts.
+     * @param alias
+     * @return
+     */
+    public Value findVariable(String alias) {
+        Value var = getVariable(alias);
+        if (var != null)
+            return var;
+        for (Context p = parent; p != null; ) {
+            var = p.getVariable(alias);
+            if (var != null)
+                return var;
+            p = p.parent;
+        }
+        return null;
+    }
+}
+

Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Path.java Mon Jul 20 17:49:36 2009
@@ -67,4 +67,15 @@
      * @return Return xmlmapping
      */
     public XMLMetaData getXmlMapping();
+
+    /**
+     * Set the schema alias (the identification variable)
+     * this path is begin with.
+     * @param schemaAlias
+     */
+    public void setSchemaAlias(String schemaAlias);
+        
+    public String getSchemaAlias();
+    
+    public void setSubqueryContext(Context context);
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java Mon Jul 20 17:49:36 2009
@@ -22,10 +22,12 @@
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Stack;
 
 import org.apache.commons.collections.map.LinkedMap;
 import org.apache.openjpa.kernel.QueryOperations;
 import org.apache.openjpa.kernel.StoreQuery;
+import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
 
@@ -69,9 +71,26 @@
     public String[] fetchInnerPaths = StoreQuery.EMPTY_STRINGS;
     public Value[] range = EMPTY_VALUES;
     private Boolean _aggregate = null;
+    private Stack<Context> _contexts = null;
     public Object state;
     
     /**
+     * Set reference to the JPQL query contexts.
+     * @param contexts
+     */
+    public void setContexts(Stack<Context> contexts) {
+        _contexts = contexts;
+    }
+
+    /**
+     * Returns the current JPQL query context.
+     * @return
+     */
+    public Context ctx() {
+        return _contexts.peek();
+    }
+
+    /**
      * Whether this is an aggregate results.
      */
     public boolean isAggregate() {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java Mon Jul 20 17:49:36 2009
@@ -41,6 +41,10 @@
         _alias = alias;
     }
 
+    public Object getSelect() {
+        return null;
+    }
+
     public String getCandidateAlias() {
         return _alias;
     }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java Mon Jul 20 17:49:36 2009
@@ -36,4 +36,6 @@
      * Set the parsed subquery.
      */
     public void setQueryExpressions(QueryExpressions query);
+
+    public Object getSelect();
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Val.java Mon Jul 20 17:49:36 2009
@@ -135,4 +135,8 @@
     public Path getPath() {
         return null;
     }
+
+    public String getName() {
+        return null;
+    }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java?rev=795934&r1=795933&r2=795934&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Value.java Mon Jul 20 17:49:36 2009
@@ -90,4 +90,6 @@
     public Value getSelectAs();
 
     public Path getPath();
+
+    public String getName();
 }