From 291f3142428888a44ff884e27f21b128d37f2a4a Mon Sep 17 00:00:00 2001 From: Fay Wang Date: Fri, 26 Jun 2009 06:34:34 +0000 Subject: [PATCH] OPENJPA-1143: correlation join support git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@788604 13f79535-47bb-0310-9956-ffa450edef68 --- .../criteria/CriteriaExpressionBuilder.java | 82 +++++---- .../openjpa/persistence/criteria/Joins.java | 163 ++++++++++++------ .../persistence/criteria/PathImpl.java | 41 +++-- .../persistence/criteria/RootImpl.java | 4 +- .../persistence/criteria/SubqueryImpl.java | 102 +++++++++-- 5 files changed, 270 insertions(+), 122 deletions(-) diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java index 5e30d2208..68c3b3541 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java @@ -49,8 +49,7 @@ import org.apache.openjpa.persistence.meta.MetamodelImpl; */ public class CriteriaExpressionBuilder { - public QueryExpressions getQueryExpressions(ExpressionFactory factory, - CriteriaQueryImpl q) { + public QueryExpressions getQueryExpressions(ExpressionFactory factory, CriteriaQueryImpl q) { QueryExpressions exps = new QueryExpressions(); //exps.setContexts(q.getContexts()); @@ -76,8 +75,7 @@ public class CriteriaExpressionBuilder { return exps; } - protected void evalAccessPaths(QueryExpressions exps, - ExpressionFactory factory, CriteriaQueryImpl q) { + protected void evalAccessPaths(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { Set metas = new HashSet(); Set> roots = q.getRoots(); if (roots != null) { @@ -88,17 +86,14 @@ public class CriteriaExpressionBuilder { for (Join join : root.getJoins()) { Class cls = join.getAttribute().getJavaType(); if (join.getAttribute().isAssociation()) { - ClassMetaData meta = metamodel.repos. - getMetaData(cls, null, true); - PersistenceType type = metamodel. - getPersistenceType(meta); - if (type == PersistenceType.ENTITY || - type == PersistenceType.EMBEDDABLE) + ClassMetaData meta = metamodel.repos.getMetaData(cls, null, true); + PersistenceType type = metamodel.getPersistenceType(meta); + if (type == PersistenceType.ENTITY || type == PersistenceType.EMBEDDABLE) metas.add(meta); } } if (root.getFetches() != null) { - for (Fetch fetch : root.getFetches()) { + for (Fetch fetch : root.getFetches()) { metas.add(metamodel.repos.getMetaData( fetch.getAttribute().getJavaType(), null, false)); @@ -110,8 +105,7 @@ public class CriteriaExpressionBuilder { exps.accessPath = metas.toArray(new ClassMetaData[metas.size()]); } - protected void evalOrdering(QueryExpressions exps, - ExpressionFactory factory, CriteriaQueryImpl q) { + protected void evalOrdering(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { List orders = q.getOrderList(); MetamodelImpl model = q.getMetamodel(); if (orders == null) @@ -124,7 +118,7 @@ public class CriteriaExpressionBuilder { for (int i = 0; i < ordercount; i++) { OrderImpl order = (OrderImpl)orders.get(i); //Expression expr = order.getExpression(); - Expression expr = order.getExpression5(); + Expression expr = order.getExpression5(); exps.ordering[i] = Expressions.toValue( (ExpressionImpl)expr, factory, model, q); @@ -134,8 +128,7 @@ public class CriteriaExpressionBuilder { } } - protected void evalGrouping(QueryExpressions exps, - ExpressionFactory factory, CriteriaQueryImpl q) { + protected void evalGrouping(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { // exps.grouping = null; // Value[] // exps.groupingClauses = null; // String[] List> groups = q.getGroupList(); @@ -155,8 +148,7 @@ public class CriteriaExpressionBuilder { : having.toKernelExpression(factory, model, q); } - protected void evalDistinct(QueryExpressions exps, - ExpressionFactory factory, CriteriaQueryImpl q) { + protected void evalDistinct(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { Boolean distinct = q.getDistinct(); if (distinct == null) { exps.distinct = QueryExpressions.DISTINCT_FALSE; @@ -167,22 +159,33 @@ public class CriteriaExpressionBuilder { //exps.distinct &= ~QueryExpressions.DISTINCT_AUTO; } - protected void evalFilter(QueryExpressions exps, ExpressionFactory factory, - CriteriaQueryImpl q) { + protected void evalFilter(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { Set> roots = q.getRoots(); MetamodelImpl model = q.getMetamodel(); PredicateImpl where = q.getRestriction(); - q.assertRoot(); + SubqueryImpl subQuery = q.getDelegator(); org.apache.openjpa.kernel.exps.Expression filter = null; - for (Root root : roots) { - if (root.getJoins() != null) { - for (Join join : root.getJoins()) { - filter = and(factory, ((ExpressionImpl)join) - .toKernelExpression(factory, model, q), filter); + if (subQuery == null || subQuery.getCorrelatedJoins() == null) { + q.assertRoot(); + for (Root root : roots) { + if (root.getJoins() != null) { + for (Join join : root.getJoins()) { + filter = and(factory, ((ExpressionImpl)join) + .toKernelExpression(factory, model, q), filter); + } } + ((RootImpl)root).addToContext(factory, model, q); } - ((RootImpl)root).addToContext(factory, model, q); } + if (subQuery != null) { + List> corrJoins = subQuery.getCorrelatedJoins(); + if (corrJoins != null) { + for (int i = 0; i < corrJoins.size(); i++) + filter = and(factory, ((ExpressionImpl)corrJoins.get(i)) + .toKernelExpression(factory, model, q), filter); + } + } + if (where != null) { filter = and(factory, where.toKernelExpression (factory, model, q), filter); @@ -192,8 +195,7 @@ public class CriteriaExpressionBuilder { exps.filter = filter; } - protected void evalProjections(QueryExpressions exps, - ExpressionFactory factory, CriteriaQueryImpl q) { + protected void evalProjections(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { List> selections = q.getSelectionList(); MetamodelImpl model = q.getMetamodel(); // TODO: fill in projection clauses @@ -212,8 +214,8 @@ public class CriteriaExpressionBuilder { } private void getProjections(QueryExpressions exps, - List> selections, List projections, List aliases, - ExpressionFactory factory, CriteriaQueryImpl q, MetamodelImpl model) { + List> selections, List projections, List aliases, + ExpressionFactory factory, CriteriaQueryImpl q, MetamodelImpl model) { for (Selection s : selections) { List> sels = ((SelectionImpl)s).getSelections(); if (sels == null) { @@ -229,14 +231,20 @@ public class CriteriaExpressionBuilder { } } - protected boolean isDefaultProjection(List> selections, - CriteriaQueryImpl q) { - return selections == null - || (selections.size() == 1 && selections.get(0) == q.getRoot()); + protected boolean isDefaultProjection(List> selections, CriteriaQueryImpl q) { + if (selections == null) + return true; + if (selections.size() != 1) + return false; + Selection sel = selections.get(0); + if (q.getRoots() != null && sel == q.getRoot()) + return true; + if ((sel instanceof PathImpl) && ((PathImpl)sel)._correlatedPath != null) + return true; + return false; } - protected void evalFetchJoin(QueryExpressions exps, - ExpressionFactory factory, CriteriaQueryImpl q) { + protected void evalFetchJoin(QueryExpressions exps, ExpressionFactory factory, CriteriaQueryImpl q) { List iPaths = new ArrayList(); List oPaths = new ArrayList(); Set> roots = q.getRoots(); diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Joins.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Joins.java index b0eb48dbe..eb328298b 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Joins.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Joins.java @@ -18,6 +18,7 @@ */ package org.apache.openjpa.persistence.criteria; +import javax.persistence.criteria.AbstractQuery; import javax.persistence.criteria.CollectionJoin; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Join; @@ -73,6 +74,10 @@ public abstract class Joins { return (FromImpl) _parent; } + public Member getMember() { + return (Member) _member; + } + /** * Return the metamodel attribute corresponding to the join. * @return metamodel attribute type corresponding to the join @@ -111,32 +116,37 @@ public abstract class Joins { SubqueryImpl subquery = c.getDelegator(); PathImpl parent = getInnermostParentPath(); org.apache.openjpa.kernel.exps.Expression filter = null; - PathImpl correlatedParent = null; + PathImpl correlatedParentPath = null; boolean bind = true; - if (parent.inSubquery(subquery)) { - org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); - path = factory.newPath(subQ); - correlatedParent = _parent.getCorrelatedParent(); - if (correlatedParent == null) { - path.setMetaData(subQ.getMetaData()); - path.get(_member.fmd, allowNull); - //path.setSchemaAlias(c.getAlias(_parent)); - } else { - bind = false; - } - } else if (c.isRegistered(_parent)) { - Value var = c.getVariable(_parent); - path = factory.newPath(var); - path.setMetaData(meta); - path.get(_member.fmd, false); - } else { - path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, model, c); - } + java.util.List> corrJoins = null; org.apache.openjpa.kernel.exps.Expression join = null; - if (bind) { - Value var = factory.newBoundVariable(c.getAlias(this), meta.getDescribedType()); - join = factory.bindVariable(var, path); - c.registerVariable(this, var, path); + if (_correlatedPath == null) { + if (subquery != null) { + corrJoins = subquery.getCorrelatedJoins(); + org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); + path = factory.newPath(subQ); + if ((corrJoins != null && corrJoins.contains(_parent)) || + (corrJoins == null && parent.inSubquery(subquery))) { + correlatedParentPath = _parent.getCorrelatedPath(); + bind = false; + } else { + path.setMetaData(subQ.getMetaData()); + path.get(_member.fmd, allowNull); + //path.setSchemaAlias(c.getAlias(_parent)); + } + } else if (c.isRegistered(_parent)) { + Value var = c.getVariable(_parent); + path = factory.newPath(var); + path.setMetaData(meta); + path.get(_member.fmd, false); + } else + path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, model, c); + + if (bind) { + Value var = factory.newBoundVariable(c.getAlias(this), meta.getDescribedType()); + join = factory.bindVariable(var, path); + c.registerVariable(this, var, path); + } } if (getJoins() != null) { for (Join join1 : getJoins()) { @@ -146,11 +156,16 @@ public abstract class Joins { } org.apache.openjpa.kernel.exps.Expression expr = CriteriaExpressionBuilder.and(factory, join, filter); - if (correlatedParent == null) { + if (correlatedParentPath == null) { return expr; } else { - org.apache.openjpa.kernel.exps.Path parentPath = (org.apache.openjpa.kernel.exps.Path) - correlatedParent.toValue(factory, model, c); + org.apache.openjpa.kernel.exps.Path parentPath = null; + if (corrJoins != null && corrJoins.contains(_parent)) { + Value var = getVariableForCorrPath(subquery, correlatedParentPath); + parentPath = factory.newPath(var); + } else + parentPath = (org.apache.openjpa.kernel.exps.Path) + correlatedParentPath.toValue(factory, model, c); parentPath.get(_member.fmd, allowNull); //parentPath.setSchemaAlias(c.getAlias(correlatedParent)); path.setMetaData(meta); @@ -159,6 +174,18 @@ public abstract class Joins { return CriteriaExpressionBuilder.and(factory, expr, filter); } } + + private Value getVariableForCorrPath(SubqueryImpl subquery, PathImpl path) { + AbstractQuery parent = subquery.getParent(); + if (parent instanceof CriteriaQueryImpl) { + return ((CriteriaQueryImpl)parent).getVariable(path); + } + Value var = ((SubqueryImpl)parent).getDelegate().getVariable(path); + if (var != null) + return var; + return getVariableForCorrPath((SubqueryImpl)parent, path); + } + } /** @@ -214,7 +241,6 @@ public abstract class Joins { @Override public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl c) { - ClassMetaData meta = getMemberClassMetaData(); org.apache.openjpa.kernel.exps.Path path = null; SubqueryImpl subquery = c.getDelegator(); PathImpl parent = getInnermostParentPath(); @@ -245,34 +271,40 @@ public abstract class Joins { ClassMetaData meta = getMemberClassMetaData(); org.apache.openjpa.kernel.exps.Path path = null; SubqueryImpl subquery = c.getDelegator(); - PathImpl parent = getInnermostParentPath(); org.apache.openjpa.kernel.exps.Expression filter = null; - PathImpl correlatedParent = null; + java.util.List> corrJoins = null; boolean bind = true; - if (parent.inSubquery(subquery)) { - org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); - path = factory.newPath(subQ); - correlatedParent = _parent.getCorrelatedParent(); - if (correlatedParent == null) { - path.setMetaData(subQ.getMetaData()); - path.get(_member.fmd, allowNull); - //path.setSchemaAlias(c.getAlias(_parent)); - } else { - bind = false; - } - } else if (c.isRegistered(_parent)) { - Value var = c.getVariable(_parent); - path = factory.newPath(var); - path.setMetaData(meta); - path.get(_member.fmd, false); - } else { - path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, model, c); - } org.apache.openjpa.kernel.exps.Expression join = null; - if (bind) { - Value var = factory.newBoundVariable(c.getAlias(this), meta.getDescribedType()); - join = factory.bindVariable(var, path); - c.registerVariable(this, var, path); + PathImpl corrJoin = getCorrelatedJoin(this); + PathImpl corrRoot = getCorrelatedRoot(subquery); + + PathImpl correlatedParentPath = null; + if (_correlatedPath == null) { + if (subquery != null) { + corrJoins = subquery.getCorrelatedJoins(); + org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); + path = factory.newPath(subQ); + if (corrJoin != null || corrRoot != null) { + correlatedParentPath = _parent.getCorrelatedPath(); + bind = false; + } else { + path.setMetaData(subQ.getMetaData()); + path.get(_member.fmd, allowNull); + //path.setSchemaAlias(c.getAlias(_parent)); + } + } else if (c.isRegistered(_parent)) { + Value var = c.getVariable(_parent); + path = factory.newPath(var); + path.setMetaData(meta); + path.get(_member.fmd, false); + } else + path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, model, c); + + if (bind) { + Value var = factory.newBoundVariable(c.getAlias(this), meta.getDescribedType()); + join = factory.bindVariable(var, path); + c.registerVariable(this, var, path); + } } if (getJoins() != null) { for (Join join1 : getJoins()) { @@ -281,19 +313,36 @@ public abstract class Joins { } } org.apache.openjpa.kernel.exps.Expression expr = CriteriaExpressionBuilder.and(factory, join, filter); - if (correlatedParent == null) { + if (correlatedParentPath == null) { return expr; } else { - org.apache.openjpa.kernel.exps.Path parentPath = (org.apache.openjpa.kernel.exps.Path) - correlatedParent.toValue(factory, model, c); + org.apache.openjpa.kernel.exps.Path parentPath = null; + if (corrJoins != null && corrJoins.contains(_parent)) { + Value var = getVariableForCorrPath(subquery, correlatedParentPath); + parentPath = factory.newPath(var); + } else + parentPath = (org.apache.openjpa.kernel.exps.Path) + correlatedParentPath.toValue(factory, model, c); + parentPath.get(_member.fmd, allowNull); - //parentPath.setSchemaAlias(c.getAlias(correlatedParent)); + //parentPath.setSchemaAlias(c.getAlias(correlatedParentPath)); path.setMetaData(meta); //filter = bindVariableForKeyPath(path, alias, filter); filter = factory.equal(parentPath, path); return CriteriaExpressionBuilder.and(factory, expr, filter); } } + + private Value getVariableForCorrPath(SubqueryImpl subquery, PathImpl path) { + AbstractQuery parent = subquery.getParent(); + if (parent instanceof CriteriaQueryImpl) { + return ((CriteriaQueryImpl)parent).getVariable(path); + } + Value var = ((SubqueryImpl)parent).getDelegate().getVariable(path); + if (var != null) + return var; + return getVariableForCorrPath((SubqueryImpl)parent, path); + } } /** diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java index cb714bf71..2e63a28ae 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java @@ -56,8 +56,8 @@ public class PathImpl extends ExpressionImpl implements Path { protected final PathImpl _parent; protected final Members.Member _member; private boolean isEmbedded = false; - private PathImpl _correlatedParent; - + protected PathImpl _correlatedPath; + /** * Protected. use by root path which neither represent a member nor has a * parent. @@ -119,12 +119,11 @@ public class PathImpl extends ExpressionImpl implements Path { parent._member); } - public void setCorrelatedParent(PathImpl correlatedParent) { - _correlatedParent = correlatedParent; + public void setCorrelatedPath(PathImpl correlatedPath) { + _correlatedPath = correlatedPath; } - - public PathImpl getCorrelatedParent() { - return _correlatedParent; + public PathImpl getCorrelatedPath() { + return _correlatedPath; } /** @@ -137,15 +136,15 @@ public class PathImpl extends ExpressionImpl implements Path { return q.getValue(this); org.apache.openjpa.kernel.exps.Path path = null; SubqueryImpl subquery = q.getDelegator(); - PathImpl parent = getInnermostParentPath(); boolean allowNull = _parent == null ? false : _parent instanceof Join && ((Join)_parent).getJoinType() != JoinType.INNER; - + PathImpl corrJoin = getCorrelatedJoin(this); + PathImpl corrRoot = getCorrelatedRoot(subquery); if (_parent != null && q.isRegistered(_parent)) { path = factory.newPath(q.getVariable(_parent)); //path.setSchemaAlias(q.getAlias(_parent)); path.get(_member.fmd, allowNull); - } else if (parent.inSubquery(subquery)) { + } else if (corrJoin != null || corrRoot != null) { org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); path = factory.newPath(subQ); path.setMetaData(subQ.getMetaData()); @@ -166,11 +165,29 @@ public class PathImpl extends ExpressionImpl implements Path { return path; } + public PathImpl getCorrelatedRoot(SubqueryImpl subquery) { + if (subquery == null) + return null; + PathImpl root = getInnermostParentPath(); + if (subquery.getRoots() != null && subquery.getRoots().contains(this)) + return root; + return null; + } + + + public PathImpl getCorrelatedJoin(PathImpl path) { + if (path._correlatedPath != null) + return path._correlatedPath; + if (path._parent == null) + return null; + return getCorrelatedJoin(path._parent); + } + /** * Affirms if this receiver occurs in the roots of the given subquery. */ public boolean inSubquery(SubqueryImpl subquery) { - return subquery != null && subquery.getRoots().contains(this); + return subquery != null && (subquery.getRoots() == null ? false : subquery.getRoots().contains(this)); } protected void traversePath(PathImpl parent, org.apache.openjpa.kernel.exps.Path path, FieldMetaData fmd) { @@ -178,7 +195,7 @@ public class PathImpl extends ExpressionImpl implements Path { && ((Join)parent).getJoinType() != JoinType.INNER; FieldMetaData fmd1 = parent._member == null ? null : parent._member.fmd; PathImpl parent1 = parent._parent; - if (parent1 == null || parent1.getCorrelatedParent() != null) { + if (parent1 == null || parent1.getCorrelatedPath() != null) { if (fmd != null) path.get(fmd, allowNull); return; diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/RootImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/RootImpl.java index d032b6b1c..b83eeefff 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/RootImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/RootImpl.java @@ -50,7 +50,7 @@ public class RootImpl extends FromImpl implements Root { } public void addToContext(ExpressionFactory factory, MetamodelImpl model, - CriteriaQueryImpl q) { + CriteriaQueryImpl q) { String alias = q.getAlias(this); Value var = factory.newBoundVariable(alias, AbstractExpressionBuilder.TYPE_OBJECT); @@ -71,11 +71,13 @@ public class RootImpl extends FromImpl implements Root { CriteriaQueryImpl c) { SubqueryImpl subquery = c.getDelegator(); Path var = null; + //String alias = c.getAlias(this); if (inSubquery(subquery)) { Subquery subQ = subquery.getSubQ(); var = factory.newPath(subQ); } else { var = factory.newPath(); + //var.setSchemaAlias(alias); } var.setMetaData(_entity.meta); return var; diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/SubqueryImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/SubqueryImpl.java index 878c1cf26..b288055c0 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/SubqueryImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/SubqueryImpl.java @@ -18,6 +18,7 @@ */ package org.apache.openjpa.persistence.criteria; +import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -26,6 +27,7 @@ import javax.persistence.criteria.AbstractQuery; import javax.persistence.criteria.CollectionJoin; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ListJoin; import javax.persistence.criteria.MapJoin; import javax.persistence.criteria.Predicate; @@ -62,6 +64,7 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { private java.util.Set> _joins; private Expression _select; private org.apache.openjpa.kernel.exps.Subquery _subq; + private List> _corrJoins = null; public SubqueryImpl(Class cls, AbstractQuery parent) { super(cls); @@ -176,7 +179,7 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { public Root correlate(Root root) { Types.Entity entity = (Types.Entity)root.getModel(); RootImpl corrRoot = new RootImpl(entity); - corrRoot.setCorrelatedParent((RootImpl)root); + corrRoot.setCorrelatedPath((RootImpl)root); Set> roots = getRoots(); if (roots == null) { roots = new LinkedHashSet>(); @@ -186,9 +189,54 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { return corrRoot; } + public List> getCorrelatedJoins() { + return _corrJoins; + } + public Join correlate(Join join) { - _delegate.from(join.getModel().getBindableJavaType()); - return join; + Join corrJoin = clone(join); + ((PathImpl)corrJoin).setCorrelatedPath((PathImpl)join); + if (_corrJoins == null) + _corrJoins = new ArrayList>(); + _corrJoins.add(corrJoin); + return corrJoin; + } + + private Join clone(Join join) { + List> members = + new ArrayList>(); + List jts = new ArrayList(); + FromImpl root = getMembers(join, members, jts); + Members.SingularAttributeImpl member = members.get(0); + JoinType jt = jts.get(0); + Join join1 = makeJoin(root, member, jt); + for (int i = 1; i < members.size(); i++) { + join1 = makeJoin((FromImpl)join1, members.get(i), jts.get(i)); + } + return join1; + } + + private Join makeJoin(FromImpl parent, Members.SingularAttributeImpl member, JoinType jt) { + return new Joins.SingularJoin(parent, member, jt); + } + + private FromImpl getMembers(Join join, List> members, + List jts) { + PathImpl parent = (PathImpl)join.getParentPath(); + Members.SingularAttributeImpl member = + (Members.SingularAttributeImpl)((Joins.SingularJoin)join).getMember(); + JoinType jt = join.getJoinType(); + FromImpl root = null; + if (parent instanceof RootImpl) { + members.add(member); + jts.add(jt); + return (FromImpl)parent; + } else { + root = getMembers((Join)parent, members, jts); + } + members.add(member); + jts.add(jt); + return root; } public CollectionJoin correlate(CollectionJoin join) { _delegate.from(join.getModel().getBindableJavaType()); @@ -225,7 +273,7 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl q) { final boolean subclasses = true; - CriteriaExpressionBuilder queryEval = new CriteriaExpressionBuilder(); + CriteriaExpressionBuilder exprBuilder = new CriteriaExpressionBuilder(); String alias = q.getAlias(this); ClassMetaData candidate = getCandidate(); _subq = factory.newSubquery(candidate, subclasses, alias); @@ -235,7 +283,7 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { //Context context = new Context(null, _subq, contexts.peek()); //contexts.push(context); //_delegate.setContexts(contexts); - QueryExpressions subexp = queryEval.getQueryExpressions(factory, + QueryExpressions subexp = exprBuilder.getQueryExpressions(factory, _delegate); _subq.setQueryExpressions(subexp); if (subexp.projections.length > 0) @@ -248,18 +296,42 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { // correlated parent, the candidate of the subquery // should be the class metadata of the collection element private ClassMetaData getCandidate() { - RootImpl root = (RootImpl)getRoot(); - PathImpl correlatedRoot = root.getCorrelatedParent(); - if (correlatedRoot != null && root.getJoins() != null) { - Join join = root.getJoins().iterator().next(); - FieldMetaData fmd = ((Members.Member)join.getAttribute()).fmd; - if (join.getAttribute().isCollection()) { - return fmd.isElementCollection() ? fmd.getEmbeddedMetaData(): fmd.getElement().getDeclaredTypeMetaData(); - } else { - return fmd.getDeclaredTypeMetaData(); - } + if (_delegate.getRoots() == null && _corrJoins != null) { + FromImpl corrJoin = (FromImpl) _corrJoins.get(0); + if (corrJoin.getJoins() != null) { + FromImpl join = (FromImpl)corrJoin.getJoins().iterator().next(); + return getInnermostCandidate(join); + } } + + RootImpl root = (RootImpl)getRoot(); + RootImpl corrRoot = (RootImpl)root.getCorrelatedPath(); + if (corrRoot != null && root.getJoins() != null) { + FromImpl join = (FromImpl) root.getJoins().iterator().next(); + return getInnermostCandidate(join); + } + return ((AbstractManagedType)root.getModel()).meta; } + private ClassMetaData getInnermostCandidate(FromImpl from) { + if (from.getJoins() != null) { + from = (FromImpl) from.getJoins().iterator().next(); + return getInnermostCandidate(from); + } + return getCandidate(from); + } + + + private ClassMetaData getCandidate(FromImpl from) { + if (from._member.fmd.getDeclaredTypeCode() == + JavaTypes.COLLECTION || + from._member.fmd.getDeclaredTypeCode() == + JavaTypes.MAP) + return from._member.fmd.isElementCollection() + ? from._member.fmd.getEmbeddedMetaData() + : from._member.fmd.getElement().getDeclaredTypeMetaData(); + return from._member.fmd.getDeclaredTypeMetaData(); + + } }