From e57f03262621b025059bd9a2d2c669d9159ea2b6 Mon Sep 17 00:00:00 2001 From: Fay Wang Date: Wed, 24 Jun 2009 06:02:17 +0000 Subject: [PATCH] OPENJPA-1143: subquery support git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@787916 13f79535-47bb-0310-9956-ffa450edef68 --- .../criteria/CriteriaExpressionBuilder.java | 7 +- .../criteria/CriteriaQueryImpl.java | 63 ++++++-- .../persistence/criteria/FromImpl.java | 6 +- .../openjpa/persistence/criteria/Joins.java | 153 ++++++++++++++---- .../persistence/criteria/PathImpl.java | 58 ++++--- .../persistence/criteria/RootImpl.java | 32 ++-- .../persistence/criteria/SubqueryImpl.java | 63 +++++++- 7 files changed, 288 insertions(+), 94 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 2eb340aca..5e30d2208 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 @@ -40,7 +40,6 @@ import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.persistence.meta.AbstractManagedType; import org.apache.openjpa.persistence.meta.Members; import org.apache.openjpa.persistence.meta.MetamodelImpl; -import org.apache.openjpa.persistence.meta.Types; /** * Converts expressions of a CriteriaQuery to kernel Expression. @@ -53,6 +52,7 @@ public class CriteriaExpressionBuilder { public QueryExpressions getQueryExpressions(ExpressionFactory factory, CriteriaQueryImpl q) { QueryExpressions exps = new QueryExpressions(); + //exps.setContexts(q.getContexts()); evalAccessPaths(exps, factory, q); //exps.alias = null; // String @@ -181,10 +181,7 @@ public class CriteriaExpressionBuilder { .toKernelExpression(factory, model, q), filter); } } - if (((RootImpl)root).getCorrelatedParent() != null) { - filter = and(factory, ((RootImpl)root) - .toKernelExpression(factory, model, q), filter); - } + ((RootImpl)root).addToContext(factory, model, q); } if (where != null) { filter = and(factory, where.toKernelExpression diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java index e530257f6..0c78692d3 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java @@ -20,16 +20,14 @@ package org.apache.openjpa.persistence.criteria; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.persistence.Parameter; +import javax.persistence.criteria.AbstractQuery; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Order; @@ -45,7 +43,6 @@ import org.apache.openjpa.kernel.StoreQuery; import org.apache.openjpa.kernel.exps.ExpressionFactory; import org.apache.openjpa.kernel.exps.QueryExpressions; import org.apache.openjpa.kernel.exps.Value; -import org.apache.openjpa.persistence.QueryImpl; import org.apache.openjpa.persistence.meta.MetamodelImpl; import org.apache.openjpa.persistence.meta.Types; @@ -73,7 +70,7 @@ public class CriteriaQueryImpl implements CriteriaQuery, AliasContext { private PredicateImpl _having; private List> _subqueries; private Boolean _distinct; - private SubqueryImpl _context; + private SubqueryImpl _delegator; // AliasContext private int aliasCount = 0; @@ -83,25 +80,38 @@ public class CriteriaQueryImpl implements CriteriaQuery, AliasContext { new HashMap, Value>(); private Map,Value> _values = new HashMap, Value>(); - private Map,String> _aliases = - new HashMap, String>(); + private Map,String> _aliases = null; + + // SubqueryContext + //private Stack _contexts = null; public CriteriaQueryImpl(MetamodelImpl model) { this._model = model; + _aliases = new HashMap, String>(); } - public void setContext(SubqueryImpl context) { - _context = context; + public CriteriaQueryImpl(MetamodelImpl model, SubqueryImpl delegator) { + this._model = model; + _delegator = delegator; + _aliases = getAliases(); + } + + public void setDelegator(SubqueryImpl delegator) { + _delegator = delegator; } - public SubqueryImpl getContext() { - return _context; + public SubqueryImpl getDelegator() { + return _delegator; } public MetamodelImpl getMetamodel() { return _model; } + //public Stack getContexts() { + // return _contexts; + //} + public CriteriaQuery distinct(boolean distinct) { _distinct = distinct; return this; @@ -319,8 +329,11 @@ public class CriteriaQueryImpl implements CriteriaQuery, AliasContext { * receiver with the help of the given {@link ExpressionFactory}. */ QueryExpressions getQueryExpressions(ExpressionFactory factory) { + //_contexts = new Stack(); + //Context context = new Context(null, null, null); + // _contexts.push(context); return new CriteriaExpressionBuilder() - .getQueryExpressions(factory, this); + .getQueryExpressions(factory, this); } public void assertRoot() { @@ -328,6 +341,30 @@ public class CriteriaQueryImpl implements CriteriaQuery, AliasContext { throw new IllegalStateException("no root is set"); } + // + // SubqueryContext + // + //public void setContexts(Stack contexts) { + // _contexts = contexts; + //} + + public CriteriaQueryImpl getInnermostParent() { + if (_delegator == null) + return this; + AbstractQuery parent = _delegator.getParent(); + if (parent instanceof CriteriaQueryImpl) + return (CriteriaQueryImpl)parent; + // parent is a SubqueryImpl + return ((SubqueryImpl)parent).getDelegate().getInnermostParent(); + } + + public Map,String> getAliases() { + CriteriaQueryImpl c = getInnermostParent(); + if (c._aliases == null) + c._aliases = new HashMap, String>(); + return c._aliases; + } + // // AliasContext management // @@ -390,6 +427,8 @@ public class CriteriaQueryImpl implements CriteriaQuery, AliasContext { _variables.put(node, var); _values.put(node, path); _aliases.put(node, alias); + //_contexts.peek().addSchema(alias, var.getMetaData()); + //_contexts.peek().addVariable(alias, var); } public boolean isRegistered(Selection selection) { diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/FromImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/FromImpl.java index f014e52bc..68703110e 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/FromImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/FromImpl.java @@ -29,7 +29,6 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ListJoin; import javax.persistence.criteria.MapJoin; import javax.persistence.criteria.SetJoin; -import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.CollectionAttribute; import javax.persistence.metamodel.ListAttribute; import javax.persistence.metamodel.MapAttribute; @@ -39,7 +38,6 @@ import javax.persistence.metamodel.SingularAttribute; import org.apache.openjpa.persistence.meta.AbstractManagedType; import org.apache.openjpa.persistence.meta.Members; -import org.apache.openjpa.persistence.meta.Types; /** * Represents a bound type, usually an entity that appears in the from clause, @@ -174,7 +172,7 @@ public class FromImpl extends PathImpl implements From { public CollectionJoin joinCollection(String attr) { - return (CollectionJoin)join(attr, JoinType.INNER); + return (CollectionJoin)join(type.getCollection(attr), JoinType.INNER); } public CollectionJoin joinCollection(String attr, JoinType jt) { @@ -182,7 +180,7 @@ public class FromImpl extends PathImpl implements From { } public ListJoin joinList(String attr) { - return (ListJoin)join(attr, JoinType.INNER); + return (ListJoin)join(type.getList(attr), JoinType.INNER); } public ListJoin joinList(String attr, JoinType jt) { 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 3a06e6b86..3041c7372 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 @@ -58,11 +58,13 @@ public abstract class Joins { public static class SingularJoin extends FromImpl implements Join{ private final JoinType joinType; + private boolean allowNull = false; public SingularJoin(FromImpl from, Members.SingularAttributeImpl member, JoinType jt) { super(from, member, member.getJavaType()); joinType = jt; + allowNull = joinType != JoinType.INNER; } public JoinType getJoinType() { @@ -85,16 +87,26 @@ public abstract class Joins { @Override public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl c) { + ClassMetaData meta = _member.fmd.getDeclaredTypeMetaData(); + org.apache.openjpa.kernel.exps.Path path = null; + SubqueryImpl subquery = c.getDelegator(); + PathImpl parent = getInnermostParentPath(); if (c.isRegistered(this)) return c.getValue(this); - boolean allowNull = joinType != JoinType.INNER; - ClassMetaData meta = _member.fmd.getDeclaredTypeMetaData(); - org.apache.openjpa.kernel.exps.Path path = - (org.apache.openjpa.kernel.exps.Path) - _parent.toValue(factory, model, c); - path.get(_member.fmd, allowNull); - path.setMetaData(meta); - path.setImplicitType(meta.getDescribedType()); + else if (parent.inSubquery(subquery)) { + org.apache.openjpa.kernel.exps.Subquery subQ = + subquery.getSubQ(); + path = factory.newPath(subQ); + path.setMetaData(subQ.getMetaData()); + //path.setSchemaAlias(c.getAlias(this)); + } else { + path = + (org.apache.openjpa.kernel.exps.Path) + _parent.toValue(factory, model, c); + path.get(_member.fmd, allowNull); + path.setMetaData(meta); + path.setImplicitType(meta.getDescribedType()); + } return path; } @@ -104,7 +116,23 @@ public abstract class Joins { CriteriaQueryImpl c) { ClassMetaData meta = _member.fmd.getDeclaredTypeMetaData(); org.apache.openjpa.kernel.exps.Path path = null; - if (c.isRegistered(_parent)) { + SubqueryImpl subquery = c.getDelegator(); + PathImpl parent = getInnermostParentPath(); + org.apache.openjpa.kernel.exps.Expression filter = null; + PathImpl correlatedParent = 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); @@ -112,12 +140,13 @@ public abstract class Joins { } else path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, model, c); - Value var = factory.newBoundVariable(c.getAlias(this), - meta.getDescribedType()); - org.apache.openjpa.kernel.exps.Expression join = factory - .bindVariable(var, path); - c.registerVariable(this, var, path); - org.apache.openjpa.kernel.exps.Expression filter = 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 (getJoins() != null) { for (Join join1 : getJoins()) { filter = CriteriaExpressionBuilder.and(factory, @@ -125,7 +154,22 @@ public abstract class Joins { toKernelExpression(factory, model, c), filter); } } - return CriteriaExpressionBuilder.and(factory, join, filter); + org.apache.openjpa.kernel.exps.Expression expr = + CriteriaExpressionBuilder.and(factory, join, filter); + + if (correlatedParent == null) + return expr; + else { + org.apache.openjpa.kernel.exps.Path parentPath = + (org.apache.openjpa.kernel.exps.Path) + correlatedParent.toValue(factory, model, c); + parentPath.get(_member.fmd, allowNull); + //parentPath.setSchemaAlias(c.getAlias(correlatedParent)); + path.setMetaData(meta); + //filter = bindVariableForKeyPath(path, alias, filter); + filter = factory.equal(parentPath, path); + return CriteriaExpressionBuilder.and(factory, expr, filter); + } } } @@ -140,11 +184,13 @@ public abstract class Joins { public static abstract class AbstractCollection extends FromImpl implements PluralJoin { final JoinType joinType; + boolean allowNull = false; public AbstractCollection(FromImpl from, Members.PluralAttributeImpl member, JoinType jt) { super(from, member, member.getBindableJavaType()); joinType = jt; + allowNull = joinType != JoinType.INNER; } public JoinType getJoinType() { @@ -167,6 +213,12 @@ public abstract class Joins { public PluralAttribute getModel() { return (PluralAttribute) _member.getType(); } + + public ClassMetaData getMemberClassMetaData() { + return _member.fmd.isElementCollection() + ? _member.fmd.getEmbeddedMetaData() + : _member.fmd.getElement().getDeclaredTypeMetaData(); + } /** * Convert this path to a kernel path (value). @@ -174,13 +226,20 @@ public abstract class Joins { @Override public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl c) { - boolean allowNull = joinType != JoinType.INNER; - ClassMetaData meta = _member.fmd.getElement() - .getDeclaredTypeMetaData(); + ClassMetaData meta = getMemberClassMetaData(); org.apache.openjpa.kernel.exps.Path path = null; + SubqueryImpl subquery = c.getDelegator(); + PathImpl parent = getInnermostParentPath(); + if (c.isRegistered(this)) { Value var = c.getVariable(this); path = factory.newPath(var); + } else if (parent.inSubquery(subquery)) { + org.apache.openjpa.kernel.exps.Subquery subQ = + subquery.getSubQ(); + path = factory.newPath(subQ); + path.setMetaData(subQ.getMetaData()); + //path.setSchemaAlias(c.getAlias(this)); } else { path = (org.apache.openjpa.kernel.exps.Path) _parent.toValue(factory, model, c); @@ -197,12 +256,25 @@ public abstract class Joins { public org.apache.openjpa.kernel.exps.Expression toKernelExpression( ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl c) { - ClassMetaData meta = _member.fmd.isElementCollection() - ? _member.fmd.getEmbeddedMetaData() - : _member.fmd.getElement().getDeclaredTypeMetaData(); - + ClassMetaData meta = getMemberClassMetaData(); org.apache.openjpa.kernel.exps.Path path = null; - if (c.isRegistered(_parent)) { + SubqueryImpl subquery = c.getDelegator(); + PathImpl parent = getInnermostParentPath(); + org.apache.openjpa.kernel.exps.Expression filter = null; + PathImpl correlatedParent = 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); @@ -210,13 +282,14 @@ public abstract class Joins { } else path = (org.apache.openjpa.kernel.exps.Path) toValue(factory, model, c); - - Value var = factory.newBoundVariable(c.getAlias(this), - meta.getDescribedType()); - org.apache.openjpa.kernel.exps.Expression join = - factory.bindVariable(var, path); - c.registerVariable(this, var, path); - org.apache.openjpa.kernel.exps.Expression filter = 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 (getJoins() != null) { for (Join join1 : getJoins()) { filter = CriteriaExpressionBuilder.and(factory, @@ -224,8 +297,22 @@ public abstract class Joins { toKernelExpression(factory, model, c), filter); } } - return CriteriaExpressionBuilder.and(factory, join, filter); - } + org.apache.openjpa.kernel.exps.Expression expr = + CriteriaExpressionBuilder.and(factory, join, filter); + if (correlatedParent == null) + return expr; + else { + org.apache.openjpa.kernel.exps.Path parentPath = + (org.apache.openjpa.kernel.exps.Path) + correlatedParent.toValue(factory, model, c); + parentPath.get(_member.fmd, allowNull); + //parentPath.setSchemaAlias(c.getAlias(correlatedParent)); + path.setMetaData(meta); + //filter = bindVariableForKeyPath(path, alias, filter); + filter = factory.equal(parentPath, path); + return CriteriaExpressionBuilder.and(factory, expr, filter); + } + } } /** 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 6dbc41782..e4fe55f75 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 @@ -23,7 +23,6 @@ import javax.persistence.criteria.Expression; import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Path; -import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Bindable; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.MapAttribute; @@ -58,7 +57,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. use by root path which neither represent a member nor has a * parent. @@ -121,6 +121,13 @@ public class PathImpl extends ExpressionImpl implements Path { parent._member); } + public void setCorrelatedParent(PathImpl correlatedParent) { + _correlatedParent = correlatedParent; + } + + public PathImpl getCorrelatedParent() { + return _correlatedParent; + } /** * Convert this path to a kernel path. @@ -131,27 +138,26 @@ public class PathImpl extends ExpressionImpl implements Path { if (q.isRegistered(this)) return q.getValue(this); org.apache.openjpa.kernel.exps.Path path = null; - SubqueryImpl subquery = q.getContext(); + SubqueryImpl subquery = q.getDelegator(); PathImpl parent = getInnermostParentPath(); - if (parent.inSubquery(subquery)) { + boolean allowNull = _parent == null ? false : _parent instanceof Join + && ((Join)_parent).getJoinType() != JoinType.INNER; + + 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)) { org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); path = factory.newPath(subQ); path.setMetaData(subQ.getMetaData()); - boolean allowNull = false; + //path.setSchemaAlias(q.getAlias(_parent)); + traversePath(_parent, path, _member.fmd); + } else if (_parent != null) { + path = (org.apache.openjpa.kernel.exps.Path) + _parent.toValue(factory, model, q); path.get(_member.fmd, allowNull); - } else if (_parent != null) { - if (q.isRegistered(_parent)) { - path = factory.newPath(q.getVariable(_parent)); - ClassMetaData meta = _member.fmd.getDeclaredTypeMetaData(); - path.setMetaData(meta); - } else { - path = (org.apache.openjpa.kernel.exps.Path) - _parent.toValue(factory, model, q); - } - boolean allowNull = _parent instanceof Join - && ((Join)_parent).getJoinType() != JoinType.INNER; - path.get(_member.fmd, allowNull); - } else { + } else if (_parent == null) { path = factory.newPath(); path.setMetaData(model.repos.getCachedMetaData(getJavaType())); } @@ -171,6 +177,22 @@ public class PathImpl extends ExpressionImpl implements Path { return subquery != null && subquery.getRoots().contains(this); } + protected void traversePath(PathImpl parent, + org.apache.openjpa.kernel.exps.Path path, FieldMetaData fmd) { + boolean allowNull = parent == null ? false : parent instanceof Join + && ((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 (fmd != null) + path.get(fmd, allowNull); + return; + } + traversePath(parent1, path, fmd1); + if (fmd != null) + path.get(fmd, allowNull); + } + /** * Return the path corresponding to the referenced * single-valued attribute. 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 2bbb0df32..847a8c1ba 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 @@ -22,7 +22,7 @@ package org.apache.openjpa.persistence.criteria; import javax.persistence.criteria.Root; import javax.persistence.metamodel.EntityType; -import org.apache.openjpa.kernel.exps.Expression; +import org.apache.openjpa.kernel.exps.AbstractExpressionBuilder; import org.apache.openjpa.kernel.exps.ExpressionFactory; import org.apache.openjpa.kernel.exps.Path; import org.apache.openjpa.kernel.exps.Subquery; @@ -39,7 +39,6 @@ import org.apache.openjpa.persistence.meta.Types; */ public class RootImpl extends FromImpl implements Root { private final Types.Entity _entity; - private RootImpl _correlatedParent; public RootImpl(Types.Entity type) { super(type); @@ -50,12 +49,18 @@ public class RootImpl extends FromImpl implements Root { return _entity; } - public void setCorrelatedParent(RootImpl correlatedParent) { - _correlatedParent = correlatedParent; - } - - public RootImpl getCorrelatedParent() { - return _correlatedParent; + public void addToContext(ExpressionFactory factory, MetamodelImpl model, + CriteriaQueryImpl q) { + String alias = q.getAlias(this); + Value var = factory.newBoundVariable(alias, + AbstractExpressionBuilder.TYPE_OBJECT); + var.setMetaData(_entity.meta); + //TODO: + //Context currContext = (Context)q.getContexts().peek(); + //currContext.addSchema(alias, _entity.meta); + //currContext.addVariable(alias, var); + //if (currContext.schemaAlias == null) + // currContext.schemaAlias = alias; } /** @@ -64,7 +69,7 @@ public class RootImpl extends FromImpl implements Root { @Override public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl c) { - SubqueryImpl subquery = c.getContext(); + SubqueryImpl subquery = c.getDelegator(); Path var = null; if (inSubquery(subquery)) { Subquery subQ = subquery.getSubQ(); @@ -85,13 +90,8 @@ public class RootImpl extends FromImpl implements Root { ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl c) { Value path = toValue(factory, model, c); Value var = factory.newBoundVariable(c.getAlias(this), - _entity.meta.getDescribedType()); - Expression exp = factory.bindVariable(var, path); - - if (_correlatedParent == null) - return exp; - Value path1 = _correlatedParent.toValue(factory, model, c); - return factory.equal(path1, path); + _entity.meta.getDescribedType()); + return factory.bindVariable(var, path); } public String toString() { 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 e6cd6faf2..e4ae8eac1 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 @@ -39,6 +39,7 @@ import org.apache.openjpa.kernel.exps.QueryExpressions; import org.apache.openjpa.kernel.exps.Value; import org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder; import org.apache.openjpa.meta.ClassMetaData; +import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.persistence.meta.AbstractManagedType; import org.apache.openjpa.persistence.meta.MetamodelImpl; import org.apache.openjpa.persistence.meta.Types; @@ -53,23 +54,47 @@ import org.apache.openjpa.persistence.meta.Types; * @param the type selected by this subquery. */ public class SubqueryImpl extends ExpressionImpl implements Subquery { - private final CriteriaQueryImpl _parent; + private final AbstractQuery _parent; private final CriteriaQueryImpl _delegate; + private final MetamodelImpl _model; private java.util.Set> _joins; private Expression _select; private org.apache.openjpa.kernel.exps.Subquery _subq; - public SubqueryImpl(Class cls, CriteriaQueryImpl parent) { + public SubqueryImpl(Class cls, AbstractQuery parent) { super(cls); _parent = parent; - _delegate = new CriteriaQueryImpl(parent.getMetamodel()); - _delegate.setContext(this); + if (parent instanceof CriteriaQueryImpl) + _model = ((CriteriaQueryImpl)parent).getMetamodel(); + else if (parent instanceof SubqueryImpl) + _model = ((SubqueryImpl)parent).getMetamodel(); + else + _model = null; + + _delegate = new CriteriaQueryImpl(_model, this); } public AbstractQuery getParent() { return _parent; } + public CriteriaQueryImpl getDelegate() { + return _delegate; + } + + public MetamodelImpl getMetamodel() { + return _model; + } + + //public Stack getContexts() { + // return getInnermostParent().getContexts(); + //} + + public CriteriaQueryImpl getInnermostParent() { + return (CriteriaQueryImpl)(((_parent instanceof CriteriaQueryImpl)) ? + _parent : ((SubqueryImpl)_parent).getInnermostParent()); + } + public Subquery select(Expression expression) { _select = expression; _delegate.select(expression); @@ -201,15 +226,41 @@ public class SubqueryImpl extends ExpressionImpl implements Subquery { final boolean subclasses = true; CriteriaExpressionBuilder queryEval = new CriteriaExpressionBuilder(); String alias = q.getAlias(this); - ClassMetaData candidate = - ((AbstractManagedType)getRoot().getModel()).meta; + ClassMetaData candidate = getCandidate(); _subq = factory.newSubquery(candidate, subclasses, alias); _subq.setMetaData(candidate); + //TODO: + //Stack contexts = getContexts(); + //Context context = new Context(null, _subq, contexts.peek()); + //contexts.push(context); + //_delegate.setContexts(contexts); QueryExpressions subexp = queryEval.getQueryExpressions(factory, _delegate); _subq.setQueryExpressions(subexp); if (subexp.projections.length > 0) JPQLExpressionBuilder.checkEmbeddable(subexp.projections[0], null); + //contexts.pop(); return _subq; } + + // if we are in a subquery against a collection from a + // correlated parent, the candidate of the subquery + // should be the class metadata of the collection element + private ClassMetaData getCandidate() { + RootImpl root = (RootImpl)getRoot(); + RootImpl correlatedRoot = (RootImpl)root.getCorrelatedParent(); + if (correlatedRoot != null && root.getJoins() != null) { + FromImpl join = (FromImpl) root.getJoins().iterator().next(); + if (join._member.fmd.getDeclaredTypeCode() == + JavaTypes.COLLECTION || + join._member.fmd.getDeclaredTypeCode() == + JavaTypes.MAP) + return join._member.fmd.isElementCollection() + ? join._member.fmd.getEmbeddedMetaData() + : join._member.fmd.getElement().getDeclaredTypeMetaData(); + return join._member.fmd.getDeclaredTypeMetaData(); + } + return ((AbstractManagedType)root.getModel()).meta; + } + }