OPENJPA-2733 subquery parameters are incorrectly assigned
patch submitted by Pawel Veselov - thanks!
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/OrderedMap.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/OrderedMap.java
index 0953dd3..79148f9 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/OrderedMap.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/OrderedMap.java
@@ -61,6 +61,7 @@
@Override
public void clear() {
+ _del.clear();
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestSubqueries.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestSubqueries.java
index d353d9a..f4e8adb 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestSubqueries.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestSubqueries.java
@@ -20,15 +20,10 @@
import java.sql.Timestamp;
+import javax.persistence.Parameter;
import javax.persistence.Tuple;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Expression;
-import javax.persistence.criteria.Join;
-import javax.persistence.criteria.JoinType;
-import javax.persistence.criteria.ListJoin;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.SetJoin;
-import javax.persistence.criteria.Subquery;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.*;
public class TestSubqueries extends CriteriaTest {
@@ -585,4 +580,66 @@
Customer.CreditRating.POOR))));
assertEquivalence(q, query);
}
+
+ public void testSubquery24() {
+
+ em.getTransaction().begin();
+
+ em.createQuery("delete from Order o where o.customer.name = 'Capricorn'").executeUpdate();
+ em.createQuery("delete from Order o").executeUpdate();
+ em.createQuery("delete from Customer c where c.name = 'Capricorn'").executeUpdate();
+
+ em.flush();
+
+ Customer c1 = new Customer();
+ c1.setAccountNum(156);
+ c1.setFirstName("John");
+ c1.setLastName("Doe");
+ c1.setName("Capricorn");
+ em.persist(c1);
+
+ Order o1 = new Order();
+ o1.setCustomer(c1);
+ em.persist(o1);
+ o1 = new Order();
+ o1.setCustomer(c1);
+ em.persist(o1);
+
+ em.flush();
+
+ // em.getTransaction().commit();
+
+ // System.out.println("CUSTOMERS: "+em.createQuery("select count(c) from Customer c").getFirstResult());
+ // System.out.println("ORDERS: "+em.createQuery("select count(c) from Order c").getFirstResult());
+
+ CriteriaQuery<Long> q = cb.createQuery(Long.class);
+ Root<Customer> root = q.from(Customer.class);
+ q.select(root.get(Customer_.accountNum));
+
+ ParameterExpression<String> testParam = cb.parameter(String.class, "param1");
+
+ Subquery<Customer> sq = q.subquery(Customer.class);
+ Root<Order> sqRoot = sq.from(Order.class);
+ sq.where(cb.and(
+ cb.equal(cb.parameter(String.class, "param2"), sqRoot.get(Order_.customer).get(Customer_.lastName)),
+ cb.equal(testParam, sqRoot.get(Order_.customer).get(Customer_.name))
+ ));
+ sq.select(sqRoot.get(Order_.customer));
+
+ q.where(cb.and(
+ cb.equal(testParam, root.get(Customer_.name)),
+ cb.in(root).value(sq)
+ ));
+
+ // em.createQuery(q).getResultList();
+ TypedQuery<Long> tq = em.createQuery(q);
+ tq.setParameter("param1", "Capricorn");
+ tq.setParameter("param2", "Doe");
+
+ assertEquals(1, tq.getResultList().size());
+
+ em.getTransaction().rollback();
+
+ }
+
}
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 034c784..7ea8a3f 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
@@ -115,11 +115,14 @@
* @param model the metamodel defines the scope of all persistent entity references.
* @param delegator the subquery which will delegate to this receiver.
*/
- CriteriaQueryImpl(MetamodelImpl model, SubqueryImpl<T> delegator) {
+ CriteriaQueryImpl(MetamodelImpl model, SubqueryImpl<T> delegator, OrderedMap params) {
this._model = model;
this._resultClass = delegator.getJavaType();
_delegator = delegator;
_aliases = getAliases();
+ if (params != null) {
+ this._params = params;
+ }
}
/**
@@ -225,8 +228,6 @@
* Registers the given parameter.
*/
void registerParameter(ParameterExpressionImpl<?> p) {
- if (_params == null)
- _params = new OrderedMap/*<ParameterExpression<?>, Class<?>*/();
if (!_params.containsKey(p)) {
p.setIndex(_params.size());
_params.put(p, p.getJavaType());
@@ -431,7 +432,7 @@
*/
public OrderedMap<Object, Class<?>> getParameterTypes() {
collectParameters(new CriteriaExpressionVisitor.ParameterVisitor(this));
- return _params == null ? StoreQuery.EMPTY_ORDERED_PARAMS : _params;
+ return _params;
}
/**
@@ -654,7 +655,7 @@
void invalidateCompilation() {
_compiled = false;
- _params = null;
+ _params.clear();
}
/**
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 58a5671..e8abe19 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
@@ -43,6 +43,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.lib.util.OrderedMap;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.ValueMetaData;
@@ -78,14 +79,18 @@
SubqueryImpl(Class<T> cls, AbstractQuery<?> parent) {
super(cls);
_parent = parent;
+ OrderedMap params;
if (parent instanceof CriteriaQueryImpl) {
_model = ((CriteriaQueryImpl<?>)parent).getMetamodel();
+ params = ((CriteriaQueryImpl<?>)parent).getParameterTypes();
} else if (parent instanceof SubqueryImpl) {
_model = ((SubqueryImpl<?>)parent).getMetamodel();
+ params = ((SubqueryImpl<?>)parent).getInnermostParent().getParameterTypes();
} else {
_model = null;
+ params = null;
}
- _delegate = new CriteriaQueryImpl<>(_model, this);
+ _delegate = new CriteriaQueryImpl<>(_model, this, params);
}
/**