OPENJPA-1094 JPA2 Query support KEY to appear in subquery

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@776117 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Catalina Wei 2009-05-18 22:23:04 +00:00
parent e5e4cc122a
commit 2ce5299a73
10 changed files with 198 additions and 10 deletions

View File

@ -21,6 +21,7 @@ package org.apache.openjpa.jdbc.kernel.exps;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor; import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.kernel.exps.Path;
import org.apache.openjpa.kernel.exps.Value; import org.apache.openjpa.kernel.exps.Value;
/** /**
@ -109,5 +110,9 @@ abstract class AbstractVal
public Value getSelectAs() { public Value getSelectAs() {
return _alias != null ? this : null; return _alias != null ? this : null;
} }
public Path getPath() {
return null;
}
} }

View File

@ -42,7 +42,7 @@ class ContainsExpression
Val val1 = getValue1(); Val val1 = getValue1();
if (contains != null && val1 instanceof PCPath) { if (contains != null && val1 instanceof PCPath) {
PCPath sql = (PCPath) val1; PCPath sql = (PCPath) val1;
String path = sql.getPath(); String path = sql.getPCPathString();
// update the count for this path // update the count for this path
Integer count = (Integer) contains.get(path); Integer count = (Integer) contains.get(path);

View File

@ -124,4 +124,11 @@ public class MapKey
public void setMetaData(ClassMetaData meta) { public void setMetaData(ClassMetaData meta) {
_meta = meta; _meta = meta;
} }
public Object toDataStoreValue(Select sel, ExpContext ctx, ExpState state,
Object val) {
KeyExpState estate = (KeyExpState) state;
return _key.toDataStoreValue(sel, ctx,
estate.key, val);
}
} }

View File

@ -218,7 +218,7 @@ public class PCPath
return xpath.toString(); return xpath.toString();
} }
public String getPath() { public String getPCPathString() {
if (_actions == null) if (_actions == null)
return (_varName == null) ? "" : _varName + "."; return (_varName == null) ? "" : _varName + ".";
@ -293,10 +293,14 @@ public class PCPath
case JavaTypes.COLLECTION: case JavaTypes.COLLECTION:
ValueMapping elem = pstate.field.getElementMapping(); ValueMapping elem = pstate.field.getElementMapping();
if (pstate.field.isElementCollection() && if (pstate.field.isElementCollection() &&
pstate.field.getElement().isEmbedded()) pstate.field.getElement().isEmbedded()) {
return ((HandlerCollectionTableFieldStrategy) Strategy strategy = pstate.field.getStrategy();
pstate.field.getStrategy()).getElementColumns( if (strategy instanceof
elem.getTypeMapping()); HandlerCollectionTableFieldStrategy)
return ((HandlerCollectionTableFieldStrategy)
strategy).getElementColumns(
elem.getTypeMapping());
}
if (pstate.joinedRel && elem.getTypeCode() == JavaTypes.PC) if (pstate.joinedRel && elem.getTypeCode() == JavaTypes.PC)
return elem.getTypeMapping().getPrimaryKeyColumns(); return elem.getTypeMapping().getPrimaryKeyColumns();
if (elem.getColumns().length > 0) if (elem.getColumns().length > 0)

View File

@ -69,7 +69,7 @@ class SubQ
} }
public Class getType() { public Class getType() {
if (_exps != null) { if (_exps != null && _type == null) {
if (_exps.projections.length == 0) if (_exps.projections.length == 0)
return _candidate.getDescribedType(); return _candidate.getDescribedType();
if (_exps.projections.length == 1) if (_exps.projections.length == 1)

View File

@ -24,6 +24,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor; import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.kernel.exps.Path;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -75,6 +76,10 @@ class Variable
return _path; return _path;
} }
public Path getPath() {
return _path;
}
/** /**
* Set the path this variable is aliased to. * Set the path this variable is aliased to.
*/ */

View File

@ -131,4 +131,8 @@ public abstract class Val
public Value getSelectAs() { public Value getSelectAs() {
return _alias != null ? this : null; return _alias != null ? this : null;
} }
public Path getPath() {
return null;
}
} }

View File

@ -88,4 +88,6 @@ public interface Value
* Return 'this' concrete class if alias is set, otherwise null * Return 'this' concrete class if alias is set, otherwise null
*/ */
public Value getSelectAs(); public Value getSelectAs();
public Path getPath();
} }

View File

@ -651,7 +651,13 @@ public class JPQLExpressionBuilder
// clause, since we might be in a subquery against a collection // clause, since we might be in a subquery against a collection
if (isPath(left)) { if (isPath(left)) {
Path path = getPath(left); Path path = getPath(left);
setCandidate(getFieldType(path.last()), alias); FieldMetaData fmd = path.last();
ClassMetaData candidate = getFieldType(fmd);
if (candidate == null && fmd.isElementCollection())
candidate = fmd.getDefiningMetaData();
setCandidate(candidate, alias);
Path subpath = factory.newPath(ctx().subquery); Path subpath = factory.newPath(ctx().subquery);
subpath.setMetaData(ctx().subquery.getMetaData()); subpath.setMetaData(ctx().subquery.getMetaData());
@ -1491,6 +1497,14 @@ public class JPQLExpressionBuilder
private Value validateMapPath(JPQLNode node, JPQLNode id) { private Value validateMapPath(JPQLNode node, JPQLNode id) {
Path path = (Path) getValue(id); Path path = (Path) getValue(id);
FieldMetaData fld = path.last(); FieldMetaData fld = path.last();
if (fld == null && ctx().subquery != null) {
Value var = getVariable(id.text, false);
if (var != null) {
path = factory.newPath(var);
fld = path.last();
}
}
if (fld != null) { if (fld != null) {
// validate the field is of type java.util.Map // validate the field is of type java.util.Map
@ -1503,7 +1517,11 @@ public class JPQLExpressionBuilder
throw parseException(EX_USER, "bad-qualified-identifier", throw parseException(EX_USER, "bad-qualified-identifier",
new Object[]{ id.text, oper}, null); new Object[]{ id.text, oper}, null);
} }
} }
else
throw parseException(EX_USER, "unknown-type",
new Object[]{ id.text}, null);
return path; return path;
} }
@ -1517,7 +1535,9 @@ public class JPQLExpressionBuilder
FieldMetaData fld = path.last(); FieldMetaData fld = path.last();
path = (Path) factory.getKey(path); path = (Path) factory.getKey(path);
ClassMetaData meta = fld.getKey().getTypeMetaData(); ClassMetaData meta = fld.getKey().getTypeMetaData();
if (inWhereClause && meta != null) if (inWhereClause && meta != null &&
fld.isElementCollection() &&
fld.getElement().getEmbeddedMetaData() != null)
// check basic type // check basic type
throw parseException(EX_USER, "bad-general-identifier", throw parseException(EX_USER, "bad-general-identifier",
new Object[]{ id.text, "KEY" }, null); new Object[]{ id.text, "KEY" }, null);

View File

@ -746,6 +746,18 @@ public class TestEmbeddable extends SingleEMFTestCase {
assertEmployee(e); assertEmployee(e);
} }
tran.commit(); tran.commit();
em.clear();
// test range variable over element collection
String[] query = {
"select e from Employee e, in (e.nickNames) n " +
" where n like '%1'",
};
for (int i = 0; i < query.length; i++) {
es = em.createQuery(query[i]).getResultList();
for (Employee e : es){
assertEmployee(e);
}
}
em.close(); em.close();
} }
@ -2145,6 +2157,25 @@ public class TestEmbeddable extends SingleEMFTestCase {
} }
tran.commit(); tran.commit();
String query[] = {
"select d from Department1 d join d.empMap e " +
" where KEY(e) > 1 order by d",
"select d from Department1 d join d.empMap e" +
" where d.deptId = KEY(e) order by d",
"select d from Department1 d " +
" where d.deptId < ANY " +
" (select KEY(e) from in(d.empMap) e) " +
" order by d",
"select d from Department1 d " +
" where d.deptId < SOME " +
" (select KEY(e) from Department1 d1, in(d1.empMap) e) " +
" order by d",
};
for (int i = 0; i < query.length; i++) {
ds1 = em.createQuery(query[i]).getResultList();
assertDepartment1(ds1.get(0));
}
em.close(); em.close();
} }
@ -2290,6 +2321,66 @@ public class TestEmbeddable extends SingleEMFTestCase {
} }
tran.commit(); tran.commit();
String imageKey1 = (String) is1.get(0).getImages().
keySet().toArray()[0];
String imageKey2 = (String) is2.get(0).getImages().
keySet().toArray()[0];
String imageKey3 = (String) is3.get(0).getImages().
keySet().toArray()[0];
String[] query = {
"select i from Item1 i" +
" where ?1 = any " +
" (select KEY(e) from Item1 i, in(i.images) e) " +
" order by i",
"select i from Item2 i" +
" where ?1 = any " +
" (select KEY(e) from Item2 i, in(i.images) e) " +
" order by i",
"select i from Item3 i" +
" where ?1 = any " +
" (select KEY(e) from Item3 i, in(i.images) e) " +
" order by i",
"select i from Item1 i" +
" where exists " +
" (select e from Item1 i, in(i.images) e" +
" where ?1 = KEY(e)) " +
" order by i",
"select i from Item2 i" +
" where exists " +
" (select e from Item2 i, in(i.images) e" +
" where ?1 = KEY(e)) " +
" order by i",
"select i from Item3 i" +
" where exists " +
" (select e from Item3 i, in(i.images) e" +
" where ?1 = KEY(e)) " +
" order by i",
};
for (int i = 0; i < query.length; i++) {
Query q = em.createQuery(query[i]);
switch (i) {
case 0:
case 3:
q.setParameter(1, imageKey1);
is1 = q.getResultList();
assertItem1(is1.get(0));
break;
case 1:
case 4:
q.setParameter(1, imageKey2);
is2 = q.getResultList();
assertItem2(is2.get(0));
break;
case 2:
case 5:
q.setParameter(1, imageKey3);
is3 = q.getResultList();
assertItem3(is3.get(0));
break;
}
}
em.close(); em.close();
} }
@ -2308,6 +2399,56 @@ public class TestEmbeddable extends SingleEMFTestCase {
assertCompany2(c); assertCompany2(c);
} }
tran.commit(); tran.commit();
em.clear();
// test KEY(e) appeared in subquery
Division d1 = (Division) ((Company1) cs1.get(0)).getOrganization().
keySet().toArray()[0];
Division d2 = (Division) ((Company2) cs2.get(0)).getOrganization().
keySet().toArray()[0];
String[] query = {
"select c from Company1 c, in(c.organization) d " +
" where KEY(d) = ?1",
"select c from Company1 c " +
" where ?1 = " +
" (select KEY(d) from Company1 c, in(c.organization) d" +
" where d.id = 1)" +
" order by c ",
"select c from Company2 c" +
" where ?1 = " +
" (select KEY(d) from Company2 c, in(c.organization) d" +
" where d.id = 3)" +
" order by c ",
"select c from Company1 c where exists" +
" (select d from in(c.organization) d" +
" where KEY(d) = ?1)" +
" order by c ",
"select c from Company2 c where exists" +
" (select d from in(c.organization) d" +
" where KEY(d) = ?1)" +
" order by c ",
};
for (int i = 0; i < query.length; i++) {
Query q = em.createQuery(query[i]);
switch (i) {
case 0:
case 1:
case 3:
q.setParameter(1, d1);
cs1 = q.getResultList();
if (cs1.size() > 0)
assertCompany1(cs1.get(0));
break;
case 2:
case 4:
q.setParameter(1, d2);
cs2 = q.getResultList();
if (cs2.size() > 0)
assertCompany2(cs2.get(0));
break;
}
}
em.close(); em.close();
} }