OPENJPA-1401 Inheritance using Join Strategy may fail in cross join JPQL

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@891476 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Catalina Wei 2009-12-16 23:31:44 +00:00
parent a05e007394
commit 9e8b0ded0b
6 changed files with 468 additions and 4 deletions

View File

@ -73,6 +73,7 @@ public class PCPath
private static final int UNBOUND_VAR = 2; private static final int UNBOUND_VAR = 2;
private static final int UNACCESSED_VAR = 3; private static final int UNACCESSED_VAR = 3;
private static final int XPATH = 4; private static final int XPATH = 4;
private static final int OBJECT_PATH = 5;
private static final Localizer _loc = Localizer.forPackage(PCPath.class); private static final Localizer _loc = Localizer.forPackage(PCPath.class);
@ -412,6 +413,22 @@ public class PCPath
_type = PATH; _type = PATH;
} }
private void checkObjectPathInheritanceTypeJoined(PathExpState pstate) {
// if this mapping is in InheritanceType.JOINED,
// then add joins
ClassMapping base = _class;
while (base.getJoinablePCSuperclassMapping() != null)
base = base.getJoinablePCSuperclassMapping();
if (base != _class) {
ClassMapping from = _class;
ClassMapping to = base;
_type = OBJECT_PATH;
for (; from != null && from != to; from = from.getJoinablePCSuperclassMapping()) {
pstate.joins = from.joinSuperclass(pstate.joins, false);
}
}
}
public FieldMetaData last() { public FieldMetaData last() {
Action act = lastFieldAction(); Action act = lastFieldAction();
return (act == null) ? null : isXPath() ? return (act == null) ? null : isXPath() ?
@ -445,7 +462,7 @@ public class PCPath
Action act = lastFieldAction(); Action act = lastFieldAction();
if (act != null && act.op == Action.GET_XPATH) if (act != null && act.op == Action.GET_XPATH)
return ((XMLMetaData) act.data).getType(); 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; boolean key = act != null && act.op == Action.GET_KEY;
if (fld != null) { if (fld != null) {
@ -529,6 +546,9 @@ public class PCPath
pstate.joins = pstate.joins.crossJoin(_candidate.getTable(), pstate.joins = pstate.joins.crossJoin(_candidate.getTable(),
rel.getTable()); rel.getTable());
if (!itr.hasNext() && isVariable()) {
checkObjectPathInheritanceTypeJoined(pstate);
}
} else { } else {
// move past the previous field, if any // move past the previous field, if any
field = (FieldMapping) ((action.op == Action.GET_XPATH) ? field = (FieldMapping) ((action.op == Action.GET_XPATH) ?
@ -626,6 +646,7 @@ public class PCPath
String subqAlias = findSubqAlias(sel); String subqAlias = findSubqAlias(sel);
pstate.joins = pstate.joins.setSubselect(subqAlias); pstate.joins = pstate.joins.setSubselect(subqAlias);
pstate.joins.setCorrelatedVariable(_schemaAlias); pstate.joins.setCorrelatedVariable(_schemaAlias);
checkObjectPathInheritanceTypeJoined(pstate);
} }
return pstate; return pstate;
@ -652,7 +673,7 @@ public class PCPath
if (sel.getParent() == null) if (sel.getParent() == null)
return false; return false;
Iterator itr = (_actions == null) ? null : _actions.iterator(); Iterator itr = (_actions == null) ? null : _actions.iterator();
boolean navigateFromRoot = false;
boolean hasVar = false; boolean hasVar = false;
boolean startsWithSubquery = false; boolean startsWithSubquery = false;
while (itr != null && itr.hasNext()) { while (itr != null && itr.hasNext()) {
@ -830,8 +851,8 @@ public class PCPath
sel.setSchemaAlias(_schemaAlias); sel.setSchemaAlias(_schemaAlias);
ClassMapping mapping = getClassMapping(state); ClassMapping mapping = getClassMapping(state);
PathExpState pstate = (PathExpState) state; PathExpState pstate = (PathExpState) state;
if (mapping == null || !pstate.joinedRel || if (_type != OBJECT_PATH && (mapping == null || !pstate.joinedRel ||
pstate.isEmbedElementColl) pstate.isEmbedElementColl))
sel.select(getColumns(state), pstate.joins); sel.select(getColumns(state), pstate.joins);
else if (_key && pstate.field.getKey().isEmbedded()) else if (_key && pstate.field.getKey().isEmbedded())
selectEmbeddedMapKey(sel, ctx, state); selectEmbeddedMapKey(sel, ctx, state);

View File

@ -0,0 +1,81 @@
/*
* 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.persistence.inheritance.jointable;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.apache.openjpa.persistence.jdbc.Index;
@Inheritance(strategy=InheritanceType.JOINED)
@Entity
@Table(name="WContractor")
public class Contractor extends Employee {
@Column(name="ContractorProp1",length=10)
@Basic
private String ctrProp1;
@ManyToOne(optional=true,cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.LAZY)
@JoinColumn(name="Dept_No",referencedColumnName="OID")
@Index
private Department dept;
public Contractor() {
}
public Contractor(String desc) {
setDescription(desc);
}
public String getCtrProp1() {
return ctrProp1;
}
public void setCtrProp1(String ctrProp1) {
this.ctrProp1 = ctrProp1;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
public boolean equals(Object other) {
if (other instanceof Contractor) {
Contractor c = (Contractor) other;
if (c.getOID() == this.getOID() &&
c.getDept() == this.getDept())
return true;
}
return false;
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.persistence.inheritance.jointable;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Inheritance(strategy=InheritanceType.JOINED)
@Entity
@Table(name="WDept")
public class Department {
@Id
@GeneratedValue(strategy=GenerationType.TABLE, generator="JWTGen")
private long OID;
@Basic
private String description;
@Column(name="DeptProp1",length=10)
@Basic
private String deptProp1;
@OneToMany(mappedBy="dept",cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.LAZY)
private java.util.Collection<Contractor> ctrs;
public Department() {
}
public Department(String desc) {
setDescription(desc);
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public long getOID() {
return OID;
}
public void setOID(long oid) {
this.OID = oid;
}
public String getDeptProp1() {
return deptProp1;
}
public void setDeptProp1(String deptProp1) {
this.deptProp1 = deptProp1;
}
public java.util.Collection<Contractor> getCtrs() {
return ctrs;
}
public void setCtrs(java.util.Collection<Contractor> ctrs) {
this.ctrs = ctrs;
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.persistence.inheritance.jointable;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table(name="WEmployee")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Employee extends Person {
@Basic
private String description;
public Employee() {
}
public void setDescription(String description) {
this.description = description;
super.setName("Name "+description);
}
public String getDescription() {
return description;
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.persistence.inheritance.jointable;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
@Entity
@Table(name="WPerson")
@Inheritance(strategy=InheritanceType.JOINED)
@TableGenerator(name="JWTGen", table="JWT_GEN", pkColumnName="PK",
valueColumnName="ID")
public abstract class Person {
@Id
@GeneratedValue(strategy=GenerationType.TABLE, generator="JWTGen")
private long OID;
@Basic
private String name;
public Person() {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public long getOID() {
return OID;
}
public void setOID(long oid) {
this.OID = oid;
}
}

View File

@ -0,0 +1,159 @@
/*
* 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.persistence.inheritance.jointable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.openjpa.persistence.test.SQLListenerTestCase;
public class TestInheritanceTypeJoinedQuery extends SQLListenerTestCase {
public void setUp() {
setUp(Contractor.class, Employee.class, Department.class, Person.class,
CLEAR_TABLES);
populate();
}
public void populate() {
EntityManager em = emf.createEntityManager();
Department d = new Department("IT");
for (int i = 0; i < 3; i++) {
Contractor c = new Contractor("ctr" + i);
c.setDept(d);
em.persist(c);
}
em.persist(d);
em.getTransaction().begin();
em.getTransaction().commit();
em.close();
}
public void testInheritanceTypeJoinedQuery() {
EntityManager em = emf.createEntityManager();
Query q = null;
String qS = null;
Department dept = null;
qS = "SELECT c.OID, c.dept FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
List<Object[]> lResult = q.getResultList();
for (Object[] resultElement : lResult) {
Long oid = (Long)resultElement[0];
dept = (Department)resultElement[1];
}
qS = "SELECT c.OID FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
for (Object resultElement : q.getResultList()) {
Long oid = (Long)resultElement;
}
qS = "SELECT d FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
for (Department aResult: (List <Department>) q.getResultList()) {
assertEquals(dept.getOID(), aResult.getOID());
}
qS = "SELECT c FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
for (Contractor aResult: (List <Contractor>) q.getResultList()) {
//System.out.println(aResult.getDescription() + ", " + aResult.getOID());
assertEquals(dept.getOID(), aResult.getDept().getOID());
}
qS = "SELECT c FROM Contractor c, Department d where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
for (Contractor aResult: (List <Contractor>) q.getResultList()) {
assertEquals(dept.getOID(), aResult.getDept().getOID());
}
qS = "SELECT c, c.OID FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
List<Object[]> cResult = q.getResultList();
Contractor contractor = null;
for (Object[] resultElement : cResult) {
contractor = (Contractor)resultElement[0];
Long oid = (Long)resultElement[1];
assertTrue(contractor.getOID() == oid);
assertEquals(dept.getOID(), contractor.getDept().getOID());
}
qS = "SELECT c.OID, c FROM Contractor c, Department d where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
List<Object[]> dResult = q.getResultList();
for (Object[] resultElement : dResult) {
Long oid = (Long)resultElement[0];
contractor = (Contractor)resultElement[1];
assertTrue(contractor.getOID() == oid);
assertEquals(dept.getOID(), contractor.getDept().getOID());
}
qS = "SELECT c, c.OID FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
List<Object[]> eResult = q.getResultList();
for (Object[] resultElement : eResult) {
Long oid = (Long)resultElement[1];
contractor = (Contractor)resultElement[0];
assertTrue(contractor.getOID() == oid);
assertEquals(dept.getOID(), contractor.getDept().getOID());
}
qS = "SELECT c.OID, c FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT'";
q = em.createQuery(qS);
List<Object[]> fResult = q.getResultList();
for (Object[] resultElement : fResult) {
Long oid = (Long)resultElement[0];
Contractor c = (Contractor)resultElement[1];
assertTrue(oid.longValue() == c.getOID());
assertEquals(dept.getOID(), c.getDept().getOID());
}
qS = "SELECT d,c FROM Department d, Contractor c where d.OID = c.dept.OID and d.description = 'IT' " +
" and c = ?1";
q = em.createQuery(qS);
q.setParameter(1, contractor);
for (Object[] aResult: (List <Object[]>) q.getResultList()) {
System.out.println(((Department)aResult[0]).getOID() + ", " + ((Contractor)aResult[1]).getOID());
assertTrue(contractor.equals(aResult[1]));
}
qS = "SELECT c,d FROM Contractor c, Department d where d.OID = c.dept.OID and d.description = 'IT' " +
" and c = ?1";
q = em.createQuery(qS);
q.setParameter(1, contractor);
for (Object[] aResult: (List <Object[]>) q.getResultList()) {
System.out.println(((Contractor)aResult[0]).getOID() + ", " + ((Department)aResult[1]).getOID());
assertTrue(contractor.equals(aResult[0]));
}
qS = "SELECT p FROM Person p ";
q = em.createQuery(qS);
for (Object aResult: (List<Object>) q.getResultList()) {
assertTrue(aResult instanceof Contractor);
}
em.close();
}
}