You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2009/07/23 04:47:11 UTC
svn commit: r796931 - in /openjpa/trunk:
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/
openjpa-persistence/src/main/java/org/apache/openjpa...
Author: ppoddar
Date: Thu Jul 23 02:47:11 2009
New Revision: 796931
URL: http://svn.apache.org/viewvc?rev=796931&view=rev
Log:
OPENJPA-1180: Parameter processing for JPA 2.0. Implements Parameter in concrete. Parameter holding structure in Query has changed for Map<String|Integer,Object> to Map<String|Integer, Parameter>. Parameters themselves hold values (a doubtful decision).
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryParameters.java (with props)
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ParameterImpl.java (with props)
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryParameter.java (with props)
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java
- copied, changed from r792583, openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java
Removed:
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java
Modified:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAQuery.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java Thu Jul 23 02:47:11 2009
@@ -65,11 +65,7 @@
public void testPositionalParameterWithNamedBindingFails() {
String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3";
Query q = em.createQuery(JPQL_POSITIONAL);
- q.setParameter("p1", INT_VALUE);
- q.setParameter("p2", STR_VALUE);
- q.setParameter("p3", DBL_VALUE);
-
- fail(q);
+ assertSetParameterFails(q, "p1", INT_VALUE);
}
public void testPositionalParameterWithInsufficientValuesFails() {
@@ -87,9 +83,7 @@
q.setParameter(1, INT_VALUE);
q.setParameter(2, STR_VALUE);
q.setParameter(3, DBL_VALUE);
- q.setParameter(4, 4);
-
- fail(q);
+ assertSetParameterFails(q, 4, 4);
}
public void testPositionalParameterWithRepeatedValuesSucceeds() {
@@ -118,8 +112,8 @@
JPQL + "WHERE p.p1=?1 AND p.p3=?3";
Query q = em.createQuery(JPQL_POSITIONAL_GAP_IN_PARAM);
q.setParameter(1, INT_VALUE);
- q.setParameter(2, STR_VALUE);
- q.setParameter(3, DBL_VALUE);
+ q.setParameter(3, DBL_VALUE);
+ assertSetParameterFails(q, 2, STR_VALUE);
fail(q);
}
@@ -137,11 +131,7 @@
public void testNamedParameterWithPositionalBindingFails() {
String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3";
Query q = em.createQuery(JPQL_NAMED);
- q.setParameter(1, INT_VALUE);
- q.setParameter(2, STR_VALUE);
- q.setParameter(3, DBL_VALUE);
-
- fail(q);
+ assertSetParameterFails(q, 1, INT_VALUE);
}
public void testNamedParameterWithInsufficientValuesFails() {
@@ -159,9 +149,7 @@
q.setParameter("p1", INT_VALUE);
q.setParameter("p2", STR_VALUE);
q.setParameter("p3", DBL_VALUE);
- q.setParameter("p4", 4);
-
- fail(q);
+ assertSetParameterFails(q, "p4", 4);
}
public void testNamedParameterWithRepeatedValuesSucceeds() {
@@ -189,30 +177,23 @@
JPQL + "WHERE p.p1=:p1 AND p.p3=:p3";
Query q = em.createQuery(JPQL_NAMED_GAP_IN_PARAM);
q.setParameter("p1", INT_VALUE);
- q.setParameter("p2", STR_VALUE);
- q.setParameter("p3", DBL_VALUE);
-
- fail(q);
+ q.setParameter("p3", DBL_VALUE);
+ assertSetParameterFails(q, "p2", STR_VALUE);
}
public void testNamedParameterWithWrongType() {
String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3";
Query q = em.createQuery(JPQL_NAMED);
q.setParameter("p1", INT_VALUE);
- q.setParameter("p2", DBL_VALUE);
- q.setParameter("p3", STR_VALUE);
-
- fail(q);
+ assertSetParameterFails(q, "p2", DBL_VALUE);
+ assertSetParameterFails(q, "p3", STR_VALUE);
}
public void testPositionalParameterWithWrongType() {
String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3";
Query q = em.createQuery(JPQL_POSITIONAL);
q.setParameter(1, INT_VALUE);
- q.setParameter(2, DBL_VALUE);
- q.setParameter(3, STR_VALUE);
-
- fail(q);
+ assertSetParameterFails(q, 2, DBL_VALUE);
}
public void testNamedParameterWithNullValue() {
@@ -221,29 +202,23 @@
Query q = em.createQuery(JPQL_POSITIONAL);
q.setParameter("p1", INT_VALUE);
q.setParameter("p2", null);
- q.setParameter("p3", null);
-
- fail(q);
+ assertSetParameterFails(q, "p3", null); // Parameter<double> can not be set to null
}
public void testPositionalParameterWithNullValue() {
String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3";
Query q = em.createQuery(JPQL_POSITIONAL);
q.setParameter(1, INT_VALUE);
- q.setParameter(2, null);
- q.setParameter(3, null);
-
- fail(q);
+ q.setParameter(2, null); // Parameter<String> can be set to null
+ assertSetParameterFails(q, 3, null); // Parameter<double> can not be set to null
}
public void testPositionalParameterWithSingleResult() {
Query q = em.createNamedQuery("JPQL_POSITIONAL");
// "SELECT p FROM Binder p WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"
q.setParameter(1, INT_VALUE);
- q.setParameter(2, null);
- q.setParameter(3, null);
-
- fail(q, true);
+ q.setParameter(2, null); // Parameter<String> can be set to null
+ assertSetParameterFails(q, 3, null); // Parameter<double> can not be set to null
}
public void testPositionalParameterWithNativeQuery() {
@@ -274,7 +249,24 @@
fail(q);
}
-
+ void assertSetParameterFails(Query q, String name, Object v) {
+ try {
+ q.setParameter(name, v);
+ fail("Expected to fail in setting named parameter [" + name + "] to a value of " + v);
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+ }
+
+ void assertSetParameterFails(Query q, int pos, Object v) {
+ try {
+ q.setParameter(pos, v);
+ fail("Expected to fail in setting positional parameter [" + pos + "] to a value of " + v);
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+ }
+
void fail(Query q) {
fail(q, false);
}
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java Thu Jul 23 02:47:11 2009
@@ -142,12 +142,11 @@
Query q = em.createQuery(JPQL_NAMED);
q.setParameter("d", d1, TemporalType.TIME);
q.setParameter("ts", d2, TemporalType.TIMESTAMP);
- q.setParameter("t", d3, TemporalType.DATE);
try {
- q.getResultList();
+ q.setParameter("t", d3, TemporalType.DATE);
fail("Expeceted " + ArgumentException.class.getName());
- } catch (ArgumentException ex) {
+ } catch (IllegalArgumentException ex) {
// good
}
}
@@ -159,16 +158,19 @@
Query q = em.createQuery(JPQL_POSITIONAL);
q.setParameter(1, d1, TemporalType.TIME);
- q.setParameter(2, d2, TemporalType.TIMESTAMP);
- q.setParameter(3, d3, TemporalType.DATE);
try {
- q.getResultList();
+ q.setParameter(2, d2, TemporalType.TIMESTAMP);
fail("Expeceted " + ArgumentException.class.getName());
- } catch (ArgumentException ex) {
- // MDD I'm assuming good == expected.
- // good
+ } catch (IllegalArgumentException ex) {
+ // expected.
}
+ try {
+ q.setParameter(3, d3, TemporalType.DATE);
+ fail("Expeceted " + ArgumentException.class.getName());
+ } catch (IllegalArgumentException ex) {
+ // expected.
+ }
}
void verifyParams(String jpql, Class<? extends Exception> error,
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java Thu Jul 23 02:47:11 2009
@@ -38,6 +38,10 @@
@NamedQueries( {
@NamedQuery(name="FindOne",
query="select s from simple s where s.name = ?1"),
+ @NamedQuery(name="SelectWithPositionalParameter",
+ query="select a from simple a where a.id=?1 and a.name=?2"),
+ @NamedQuery(name="SelectWithNamedParameter",
+ query="select a from simple a where a.id=:id and a.name=:name"),
@NamedQuery(name="FindOne",
query="select s from simple s where s.name = ?1"),
@NamedQuery(name="FindAll", query="select s from simple s")
@@ -57,7 +61,9 @@
@Entity(name = "simple")
@Table(name = "SIMPLE_ENTITY")
public class SimpleEntity implements Serializable {
-
+ public static final String NAMED_QUERY_WITH_POSITIONAL_PARAMS = "SelectWithPositionalParameter";
+ public static final String NAMED_QUERY_WITH_NAMED_PARAMS = "SelectWithNamedParameter";
+
@Id
@GeneratedValue
@Column(name = "ID")
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryParameters.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryParameters.java?rev=796931&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryParameters.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryParameters.java Thu Jul 23 02:47:11 2009
@@ -0,0 +1,335 @@
+package org.apache.openjpa.persistence.query;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Parameter;
+import javax.persistence.Query;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.QueryBuilder;
+import javax.persistence.criteria.Root;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.Metamodel;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.openjpa.kernel.QueryLanguages;
+import org.apache.openjpa.kernel.jpql.JPQLParser;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.persistence.ParameterImpl;
+import org.apache.openjpa.persistence.QueryParameter;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Tests query parameters.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public class TestQueryParameters extends SingleEMFTestCase {
+ private static OpenJPAEntityManagerFactorySPI oemf;
+ private EntityManager em;
+
+ public void setUp() {
+ if (oemf == null) {
+ super.setUp(SimpleEntity.class, "openjpa.DynamicEnhancementAgent", "false");
+ oemf = (OpenJPAEntityManagerFactorySPI)OpenJPAPersistence.cast(emf);
+ }
+ em = oemf.createEntityManager();
+ }
+
+ public void tearDown() {
+ // do not close the factory
+ }
+
+ public void testPositionalParameterInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=?1 and e.name=?2";
+ Query q = em.createQuery(jpql)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ assertEquals(2, q.getParameters().size());
+ Parameter<?> param1 = q.getParameter(1);
+ Parameter<?> param2 = q.getParameter(2);
+
+ assertEquals(100, q.getParameterValue(1));
+ assertEquals(100, q.getParameterValue(param1));
+ assertEquals("XYZ", q.getParameterValue(2));
+ assertEquals("XYZ", q.getParameterValue(param2));
+
+ q.getResultList();
+ }
+
+ public void testNamedParameterInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=:id and e.name=:name";
+ Query q = em.createQuery(jpql)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ assertEquals(2, q.getParameters().size());
+ Parameter<?> param1 = q.getParameter("id");
+ Parameter<?> param2 = q.getParameter("name");
+
+ assertEquals(100, q.getParameterValue("id"));
+ assertEquals(100, q.getParameterValue(param1));
+ assertEquals("XYZ", q.getParameterValue("name"));
+ assertEquals("XYZ", q.getParameterValue(param2));
+
+ q.getResultList();
+ }
+
+ public void testPositionalParameterMissingInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=?1 and e.name=?2";
+ Query q = em.createQuery(jpql)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ assertSetParameterFails(q, 3, 100); // wrong position
+ }
+
+ public void testNamedParameterMissingInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=:id and e.name=:name";
+ Query q = em.createQuery(jpql)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ assertSetParameterFails(q, "xyz", 100); // wrong name
+ }
+
+ public void testPositionalParameterWrongValueInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=?1 and e.name=?2";
+ Query q = em.createQuery(jpql)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ assertSetParameterFails(q, 1, "XYZ"); // wrong value
+ assertSetParameterFails(q, 2, 100); // wrong value
+ }
+
+ public void testNamedParameterWrongValueInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=:id and e.name=:name";
+ Query q = em.createQuery(jpql)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ assertSetParameterFails(q, "id", "XYZ"); // wrong value
+ assertSetParameterFails(q, "name", 100); // wrong value
+ }
+
+ public void testPositionalParameterValueTypeInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=?1 and e.name=?2";
+ Query q = em.createQuery(jpql)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ Parameter<?> param1 = q.getParameter(1);
+ assertTrue(param1 instanceof ParameterImpl);
+ assertEquals(long.class, ((QueryParameter<?>)param1).getExpectedValueType());
+
+ Parameter<?> param2 = q.getParameter(2);
+ assertTrue(param2 instanceof ParameterImpl);
+ assertEquals(String.class, ((QueryParameter<?>)param2).getExpectedValueType());
+ }
+
+ public void testNamedParameterValueTypeInJPQLQuery() {
+ String jpql = "select e from simple e WHERE e.id=:id and e.name=:name";
+ Query q = em.createQuery(jpql)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ Parameter<?> param1 = q.getParameter("id");
+ assertTrue(param1 instanceof ParameterImpl);
+ assertEquals(long.class, ((QueryParameter<?>)param1).getExpectedValueType());
+
+ Parameter<?> param2 = q.getParameter("name");
+ assertTrue(param2 instanceof ParameterImpl);
+ assertEquals(String.class, ((QueryParameter<?>)param2).getExpectedValueType());
+ }
+
+ public void testNamedParameterInPreparedQuery() {
+ String jpql = "select x from simple x WHERE x.id=:id and x.name=:name";
+ Query q = em.createQuery(jpql)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+ q.getResultList();
+
+ assertEquals(JPQLParser.LANG_JPQL, OpenJPAPersistence.cast(q).getLanguage());
+
+ Query q2 = em.createQuery(jpql)
+ .setParameter("id", 200)
+ .setParameter("name", "ZXY");
+
+ assertEquals(QueryLanguages.LANG_PREPARED_SQL, OpenJPAPersistence.cast(q2).getLanguage());
+ q2.getResultList();
+ }
+
+ //--------------------------------------------------------------------------------------------
+ // Similar tests with NamedQuery
+ //--------------------------------------------------------------------------------------------
+ public void testPositionalParameterInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_POSITIONAL_PARAMS)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ assertEquals(2, q.getParameters().size());
+ Parameter<?> param1 = q.getParameter(1);
+ Parameter<?> param2 = q.getParameter(2);
+
+ assertEquals(100, q.getParameterValue(1));
+ assertEquals(100, q.getParameterValue(param1));
+ assertEquals("XYZ", q.getParameterValue(2));
+ assertEquals("XYZ", q.getParameterValue(param2));
+
+ q.getResultList();
+ }
+
+ public void testNamedParameterInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_NAMED_PARAMS)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ assertEquals(2, q.getParameters().size());
+ Parameter<?> param1 = q.getParameter("id");
+ Parameter<?> param2 = q.getParameter("name");
+
+ assertEquals(100, q.getParameterValue("id"));
+ assertEquals(100, q.getParameterValue(param1));
+ assertEquals("XYZ", q.getParameterValue("name"));
+ assertEquals("XYZ", q.getParameterValue(param2));
+
+ q.getResultList();
+ }
+
+ public void testPositionalParameterMissingInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_POSITIONAL_PARAMS)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ assertSetParameterFails(q, 3, 100); // wrong position
+ }
+
+ public void testNamedParameterMissingInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_NAMED_PARAMS)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ assertSetParameterFails(q, "xyz", 100); // wrong name
+ }
+
+ public void testPositionalParameterWrongValueInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_POSITIONAL_PARAMS)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ assertSetParameterFails(q, 1, "XYZ"); // wrong value
+ assertSetParameterFails(q, 2, 100); // wrong value
+ }
+
+ public void testNamedParameterWrongValueInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_NAMED_PARAMS)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ assertSetParameterFails(q, "id", "XYZ"); // wrong value
+ assertSetParameterFails(q, "name", 100); // wrong value
+ }
+
+ public void testPositionalParameterValueTypeInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_POSITIONAL_PARAMS)
+ .setParameter(1, 100)
+ .setParameter(2, "XYZ");
+
+ Parameter<?> param1 = q.getParameter(1);
+ assertTrue(param1 instanceof ParameterImpl);
+ assertEquals(long.class, ((QueryParameter<?>)param1).getExpectedValueType());
+
+ Parameter<?> param2 = q.getParameter(2);
+ assertTrue(param2 instanceof ParameterImpl);
+ assertEquals(String.class, ((QueryParameter<?>)param2).getExpectedValueType());
+ }
+
+ public void testNamedParameterValueTypeInNamedQuery() {
+ Query q = em.createNamedQuery(SimpleEntity.NAMED_QUERY_WITH_NAMED_PARAMS)
+ .setParameter("id", 100)
+ .setParameter("name", "XYZ");
+
+ Parameter<?> param1 = q.getParameter("id");
+ assertTrue(param1 instanceof ParameterImpl);
+ assertEquals(long.class, ((QueryParameter<?>)param1).getExpectedValueType());
+
+ Parameter<?> param2 = q.getParameter("name");
+ assertTrue(param2 instanceof ParameterImpl);
+ assertEquals(String.class, ((QueryParameter<?>)param2).getExpectedValueType());
+ }
+
+ public void testCriteriaQueryWithNamedParameter() {
+ Metamodel model = oemf.getMetamodel();
+ EntityType<SimpleEntity> entity = model.entity(SimpleEntity.class);
+ SingularAttribute<SimpleEntity, Long> id =
+ (SingularAttribute<SimpleEntity, Long>)entity.getSingularAttribute("id");
+ SingularAttribute<SimpleEntity, String> name =
+ (SingularAttribute<SimpleEntity, String>)entity.getSingularAttribute("name");
+
+ QueryBuilder cb = oemf.getQueryBuilder();
+ CriteriaQuery<SimpleEntity> c = cb.createQuery(SimpleEntity.class);
+ Root<SimpleEntity> root = c.from(SimpleEntity.class);
+ ParameterExpression<Long> param1 = cb.parameter(long.class, "id");
+ ParameterExpression<String> param2 = cb.parameter(String.class, "name");
+ Predicate p1 = cb.equal(root.get(id), param1);
+ Predicate p2 = cb.equal(root.get(name), param2);
+ c.where(cb.and(p1,p2));
+
+ Query q = em.createQuery(c);
+ assertEquals(2, q.getParameters().size());
+ assertTrue(q.getParameters().contains(param1));
+ assertTrue(q.getParameters().contains(param2));
+ }
+
+ public void testCriteriaQueryWithUnnamedParameter() {
+ Metamodel model = oemf.getMetamodel();
+ EntityType<SimpleEntity> entity = model.entity(SimpleEntity.class);
+ SingularAttribute<SimpleEntity, Long> id =
+ (SingularAttribute<SimpleEntity, Long>)entity.getSingularAttribute("id");
+ SingularAttribute<SimpleEntity, String> name =
+ (SingularAttribute<SimpleEntity, String>)entity.getSingularAttribute("name");
+
+ QueryBuilder cb = oemf.getQueryBuilder();
+ CriteriaQuery<SimpleEntity> c = cb.createQuery(SimpleEntity.class);
+ Root<SimpleEntity> root = c.from(SimpleEntity.class);
+ ParameterExpression<Long> param1 = cb.parameter(long.class);
+ ParameterExpression<String> param2 = cb.parameter(String.class);
+ Predicate p1 = cb.equal(root.get(id), param1);
+ Predicate p2 = cb.equal(root.get(name), param2);
+ c.where(cb.and(p1,p2));
+
+ Query q = em.createQuery(c);
+ assertEquals(2, q.getParameters().size());
+ assertTrue(q.getParameters().contains(param1));
+ assertTrue(q.getParameters().contains(param2));
+ }
+
+
+
+ void assertSetParameterFails(Query q, String name, Object v) {
+ try {
+ q.setParameter(name, v);
+ fail("Expected " + IllegalArgumentException.class.getName());
+ } catch (IllegalArgumentException e) {
+ // good
+ System.err.println("Following is expeceted exception, printing to verify error message");
+ System.err.println(e);
+ }
+ }
+
+ void assertSetParameterFails(Query q, int pos, Object v) {
+ try {
+ q.setParameter(pos, v);
+ fail("Expected " + IllegalArgumentException.class.getName());
+ } catch (IllegalArgumentException e) {
+ // good
+ System.err.println("Following is expeceted exception, printing to verify error message");
+ System.err.println(e);
+ }
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryParameters.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java Thu Jul 23 02:47:11 2009
@@ -43,6 +43,7 @@
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.QueryBuilder;
import javax.persistence.metamodel.Metamodel;
@@ -72,6 +73,7 @@
import org.apache.openjpa.meta.QueryMetaData;
import org.apache.openjpa.meta.SequenceMetaData;
import org.apache.openjpa.persistence.criteria.CriteriaBuilder;
+import org.apache.openjpa.persistence.criteria.CriteriaQueryImpl;
import org.apache.openjpa.persistence.validation.ValidationUtils;
import org.apache.openjpa.util.Exceptions;
import org.apache.openjpa.util.ImplHelper;
@@ -1527,9 +1529,20 @@
_broker.detach(entity, this);
}
+ /**
+ * Crete a query from the given CritriaQuery.
+ * Compile to register the parameters in this query.
+ */
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
- return new QueryImpl(this, _ret,
- _broker.newQuery(CriteriaBuilder.LANG_CRITERIA, criteriaQuery));
+ org.apache.openjpa.kernel.Query kernelQuery =_broker.newQuery(CriteriaBuilder.LANG_CRITERIA, criteriaQuery);
+ kernelQuery.compile();
+ QueryImpl<T> facadeQuery = new QueryImpl<T>(this, _ret, kernelQuery);
+ Set<ParameterExpression<?>> params = ((CriteriaQueryImpl<T>)criteriaQuery).getParameters();
+
+ for (ParameterExpression<?> param : params) {
+ facadeQuery.registerParameter((QueryParameter<?>)param);
+ }
+ return facadeQuery;
}
public OpenJPAQuery createDynamicQuery(
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAQuery.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAQuery.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAQuery.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAQuery.java Thu Jul 23 02:47:11 2009
@@ -21,10 +21,8 @@
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
-import java.util.List;
import java.util.Map;
import javax.persistence.FlushModeType;
-import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
@@ -79,7 +77,7 @@
/**
* Whether to ignore changes in the current transaction.
*/
- public OpenJPAQuery setIgnoreChanges(boolean ignore);
+ public OpenJPAQuery<X>setIgnoreChanges(boolean ignore);
/**
* Return the candidate collection, or <code>null</code> if an
@@ -90,7 +88,7 @@
/**
* Set a collection of candidates.
*/
- public OpenJPAQuery setCandidateCollection(Collection coll);
+ public OpenJPAQuery<X> setCandidateCollection(Collection coll);
/**
* Query result element type.
@@ -100,7 +98,7 @@
/**
* Query result element type.
*/
- public OpenJPAQuery setResultClass(Class type);
+ public OpenJPAQuery<X> setResultClass(Class type);
/**
* Whether subclasses are included in the query results.
@@ -110,7 +108,7 @@
/**
* Whether subclasses are included in the query results.
*/
- public OpenJPAQuery setSubclasses(boolean subs);
+ public OpenJPAQuery<X> setSubclasses(boolean subs);
/**
* Return the 0-based start index for the returned results.
@@ -126,7 +124,7 @@
/**
* Compile the query.
*/
- public OpenJPAQuery compile();
+ public OpenJPAQuery<X> compile();
/**
* Whether this query has positional parameters.
@@ -148,17 +146,17 @@
/**
* Set parameters.
*/
- public OpenJPAQuery setParameters(Map params);
+ public OpenJPAQuery<X> setParameters(Map params);
/**
* Set parameters.
*/
- public OpenJPAQuery setParameters(Object... params);
+ public OpenJPAQuery<X> setParameters(Object... params);
/**
* Close all open query results.
*/
- public OpenJPAQuery closeAll();
+ public OpenJPAQuery<X>closeAll();
/**
* Returns a description of the commands that will be sent to
@@ -169,29 +167,29 @@
*/
public String[] getDataStoreActions(Map params);
- public OpenJPAQuery setMaxResults(int maxResult);
+ public OpenJPAQuery<X> setMaxResults(int maxResult);
- public OpenJPAQuery setFirstResult(int startPosition);
+ public OpenJPAQuery<X> setFirstResult(int startPosition);
- public OpenJPAQuery setHint(String hintName, Object value);
+ public OpenJPAQuery<X> setHint(String hintName, Object value);
- public OpenJPAQuery setParameter(String name, Object value);
+ public OpenJPAQuery<X> setParameter(String name, Object value);
- public OpenJPAQuery setParameter(String name, Date value,
+ public OpenJPAQuery<X> setParameter(String name, Date value,
TemporalType temporalType);
- public OpenJPAQuery setParameter(String name, Calendar value,
+ public OpenJPAQuery<X> setParameter(String name, Calendar value,
TemporalType temporalType);
- public OpenJPAQuery setParameter(int position, Object value);
+ public OpenJPAQuery<X> setParameter(int position, Object value);
- public OpenJPAQuery setParameter(int position, Date value,
+ public OpenJPAQuery<X> setParameter(int position, Date value,
TemporalType temporalType);
- public OpenJPAQuery setParameter(int position, Calendar value,
+ public OpenJPAQuery<X> setParameter(int position, Calendar value,
TemporalType temporalType);
- public OpenJPAQuery setFlushMode(FlushModeType flushMode);
+ public OpenJPAQuery<X> setFlushMode(FlushModeType flushMode);
/**
* Return the current flush mode.
@@ -233,27 +231,27 @@
* @deprecated cast to {@link QueryImpl} instead. This
* method pierces the published-API boundary, as does the SPI cast.
*/
- public OpenJPAQuery addFilterListener(
+ public OpenJPAQuery<X> addFilterListener(
org.apache.openjpa.kernel.exps.FilterListener listener);
/**
* @deprecated cast to {@link QueryImpl} instead. This
* method pierces the published-API boundary, as does the SPI cast.
*/
- public OpenJPAQuery removeFilterListener(
+ public OpenJPAQuery<X> removeFilterListener(
org.apache.openjpa.kernel.exps.FilterListener listener);
/**
* @deprecated cast to {@link QueryImpl} instead. This
* method pierces the published-API boundary, as does the SPI cast.
*/
- public OpenJPAQuery addAggregateListener(
+ public OpenJPAQuery<X> addAggregateListener(
org.apache.openjpa.kernel.exps.AggregateListener listener);
/**
* @deprecated cast to {@link QueryImpl} instead. This
* method pierces the published-API boundary, as does the SPI cast.
*/
- public OpenJPAQuery removeAggregateListener(
+ public OpenJPAQuery<X> removeAggregateListener(
org.apache.openjpa.kernel.exps.AggregateListener listener);
}
Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ParameterImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ParameterImpl.java?rev=796931&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ParameterImpl.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ParameterImpl.java Thu Jul 23 02:47:11 2009
@@ -0,0 +1,204 @@
+/*
+ * 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;
+
+import javax.persistence.Parameter;
+
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.lib.util.Localizer;
+
+/**
+ * A user-defined parameter of a query.
+ *
+ * A parameter is uniquely identified within the scope of a query by either
+ * its name or integral position. The integral position refers to the integer
+ * key as specified by the user. The index of this parameter during execution
+ * in a datastore query may be different.
+ * <br>
+ * A value can be bound to this parameter. This behavior of a parameter carrying
+ * its own value is a change from earlier versions (where no explicit abstraction
+ * existed for a query parameter).
+ *
+ * @author Pinaki Poddar
+ *
+ * @since 2.0.0
+ *
+ * @param <T> type of value carried by this parameter.
+ *
+ */
+public class ParameterImpl<T> implements QueryParameter<T> {
+ private static final Localizer _loc = Localizer.forPackage(ParameterImpl.class);
+
+ private final String _name;
+ private final Integer _position;
+ private final Class<?> _expectedValueType;
+ private Object _value;
+ private boolean _bound;
+
+ /**
+ * Construct a positional parameter with the given position as key and
+ * no expected value type.
+ */
+ public ParameterImpl(int position) {
+ this(position, null);
+ }
+
+ /**
+ * Construct a positional parameter with the given position as key and
+ * given expected value type.
+ */
+ public ParameterImpl(int position, Class<?> expectedValueType) {
+ _name = null;
+ _position = position;
+ _expectedValueType = expectedValueType;
+ }
+
+ /**
+ * Construct a named parameter with the given name as key and
+ * no expected value type.
+ */
+ public ParameterImpl(String name) {
+ this(name, null);
+ }
+
+ /**
+ * Construct a named parameter with the given name as key and
+ * given expected value type.
+ */
+ public ParameterImpl(String name, Class<?> expectedValueType) {
+ _name = name;
+ _position = null;
+ _expectedValueType = expectedValueType;
+ }
+
+ public final String getName() {
+ return _name;
+ }
+
+ public final Integer getPosition() {
+ return _position;
+ }
+
+ public final boolean isNamed() {
+ return _name != null;
+ }
+
+ public final boolean isPositional() {
+ return _position != null;
+ }
+
+ /**
+ * Affirms if the given value can be assigned to this parameter.
+ *
+ * If no expected value type is set, then always returns true.
+ */
+ public boolean isValueAssignable(Object v) {
+ if (_expectedValueType == null)
+ return true;
+ if (v == null)
+ return !_expectedValueType.isPrimitive();
+ return Filters.canConvert(v.getClass(), _expectedValueType, true);
+ }
+
+ /**
+ * Affirms if this parameter has been bound to a value.
+ */
+ public boolean isBound() {
+ return _bound;
+ }
+
+ /**
+ * Binds the given value to this parameter.
+ *
+ * @exception if the given value is not permissible for this parameter.
+ */
+ public QueryParameter<T> bindValue(Object v) {
+ if (!isValueAssignable(v)) {
+ if (v == null)
+ throw new IllegalArgumentException(_loc.get("param-null-not-assignable", this).getMessage());
+ else
+ throw new IllegalArgumentException(_loc.get("param-value-not-assignable", this, v, v.getClass())
+ .getMessage());
+ }
+ _value = v;
+ _bound = true;
+ return this;
+ }
+
+ /**
+ * Gets the current value irrespective of whether a value has been bound or not.
+ */
+ public Object getValue() {
+ return getValue(false);
+ }
+
+ /**
+ * Gets the current value only if a value has been bound or not.
+ */
+ public Object getValue(boolean mustBeBound) {
+ if (mustBeBound && !isBound())
+ throw new IllegalStateException(_loc.get("param-not-bound", this).getMessage());
+ return _value;
+ }
+
+ /**
+ * Clears bound value.
+ */
+ public void clearBinding() {
+ _bound = false;
+ _value = null;
+ }
+
+ /**
+ * Gets (immutable) type of expected value of this parameter.
+ */
+ public Class<?> getExpectedValueType() {
+ return _expectedValueType;
+ }
+
+ /**
+ * Equals if the other parameter has the same name or position.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ if (!(other instanceof Parameter))
+ return false;
+ Parameter<?> that = (Parameter<?>)other;
+ if (isNamed())
+ return this.getName().equals(that.getName());
+ if (isPositional())
+ return getPosition().equals(that.getPosition());
+ return false;
+ }
+
+ public String toString() {
+ StringBuilder buf = new StringBuilder("Parameter");
+ buf.append("<" + (getExpectedValueType() == null ? "?" : getExpectedValueType().getName()) + ">");
+ if (isNamed()) {
+ buf.append("('" + getName() + "':");
+ } else if (isPositional()) {
+ buf.append("(" + getPosition() + ":");
+ }
+ buf.append((isBound() ? getValue() : "UNBOUND") + ")");
+
+ return buf.toString();
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ParameterImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java Thu Jul 23 02:47:11 2009
@@ -23,12 +23,13 @@
import java.io.Serializable;
import java.sql.Time;
import java.sql.Timestamp;
-import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -73,18 +74,18 @@
* @author Abe White
* @nojavadoc
*/
+@SuppressWarnings("serial")
public class QueryImpl<X> implements OpenJPAQuerySPI<X>, Serializable {
private static final Object[] EMPTY_ARRAY = new Object[0];
- private static final String SELECT = "SELECT ";
private static final Localizer _loc = Localizer.forPackage(QueryImpl.class);
private DelegatingQuery _query;
private transient EntityManagerImpl _em;
private transient FetchPlan _fetch;
- private Map<String, Object> _named;
- private Map<Integer, Object> _positional;
+ private Map<String, QueryParameter<?>> _named;
+ private Map<Integer, QueryParameter<?>> _positional;
private String _id;
private transient ReentrantLock _lock = null;
private final HintHandler _hintHandler;
@@ -156,41 +157,41 @@
return _query.getIgnoreChanges();
}
- public OpenJPAQuery setIgnoreChanges(boolean ignore) {
+ public OpenJPAQuery<X> setIgnoreChanges(boolean ignore) {
_em.assertNotCloseInvoked();
_query.setIgnoreChanges(ignore);
return this;
}
- public OpenJPAQuery addFilterListener(FilterListener listener) {
+ public OpenJPAQuery<X> addFilterListener(FilterListener listener) {
_em.assertNotCloseInvoked();
_query.addFilterListener(listener);
return this;
}
- public OpenJPAQuery removeFilterListener(FilterListener listener) {
+ public OpenJPAQuery<X> removeFilterListener(FilterListener listener) {
_em.assertNotCloseInvoked();
_query.removeFilterListener(listener);
return this;
}
- public OpenJPAQuery addAggregateListener(AggregateListener listener) {
+ public OpenJPAQuery<X> addAggregateListener(AggregateListener listener) {
_em.assertNotCloseInvoked();
_query.addAggregateListener(listener);
return this;
}
- public OpenJPAQuery removeAggregateListener(AggregateListener listener) {
+ public OpenJPAQuery<X> removeAggregateListener(AggregateListener listener) {
_em.assertNotCloseInvoked();
_query.removeAggregateListener(listener);
return this;
}
- public Collection getCandidateCollection() {
+ public Collection<?> getCandidateCollection() {
return _query.getCandidateCollection();
}
- public OpenJPAQuery setCandidateCollection(Collection coll) {
+ public OpenJPAQuery<X> setCandidateCollection(Collection coll) {
_em.assertNotCloseInvoked();
_query.setCandidateCollection(coll);
return this;
@@ -216,9 +217,9 @@
return _query.hasSubclasses();
}
- public OpenJPAQuery setSubclasses(boolean subs) {
+ public OpenJPAQuery<X> setSubclasses(boolean subs) {
_em.assertNotCloseInvoked();
- Class cls = _query.getCandidateType();
+ Class<?> cls = _query.getCandidateType();
_query.setCandidateExtent(_query.getBroker().newExtent(cls, subs));
return this;
}
@@ -227,7 +228,7 @@
return asInt(_query.getStartRange());
}
- public OpenJPAQuery setFirstResult(int startPosition) {
+ public OpenJPAQuery<X> setFirstResult(int startPosition) {
_em.assertNotCloseInvoked();
long end;
if (_query.getEndRange() == Long.MAX_VALUE)
@@ -243,7 +244,7 @@
return asInt(_query.getEndRange() - _query.getStartRange());
}
- public OpenJPAQuery setMaxResults(int max) {
+ public OpenJPAQuery<X> setMaxResults(int max) {
_em.assertNotCloseInvoked();
long start = _query.getStartRange();
if (max == Integer.MAX_VALUE)
@@ -253,20 +254,33 @@
return this;
}
- public OpenJPAQuery compile() {
+ public OpenJPAQuery<X> compile() {
_em.assertNotCloseInvoked();
_query.compile();
return this;
}
+ /**
+ * Gets a map of values of each parameter indexed by their original key.
+ *
+ * @return an empty map if no parameter is registered for this query.
+ */
+ Map<?,?> getParameterValues() {
+ Map<?,QueryParameter<?>> params = _positional != null ? _positional
+ : _named != null ? _named : new HashMap();
+ Map result = new LinkedHashMap();
+ for (Map.Entry<?,QueryParameter<?>> entry : params.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().getValue());
+ }
+ return result;
+ }
+
private Object execute() {
if (!isNative() && _query.getOperation() != QueryOperations.OP_SELECT)
- throw new InvalidStateException(_loc.get("not-select-query", _query
- .getQueryString()), null, null, false);
+ throw new InvalidStateException(_loc.get("not-select-query", getQueryString()), null, null, false);
try {
lock();
- Map params = _positional != null ? _positional
- : _named != null ? _named : new HashMap();
+ Map params = getParameterValues();
boolean registered = preExecute(params);
Object result = _query.execute(params);
if (registered) {
@@ -316,24 +330,14 @@
public int executeUpdate() {
_em.assertNotCloseInvoked();
+ Map<?,?> paramValues = getParameterValues();
if (_query.getOperation() == QueryOperations.OP_DELETE) {
- // handle which types of parameters we are using, if any
- if (_positional != null)
- return asInt(_query.deleteAll(_positional));
- if (_named != null)
- return asInt(_query.deleteAll(_named));
- return asInt(_query.deleteAll());
+ return asInt(paramValues.isEmpty() ? _query.deleteAll() : _query.deleteAll(paramValues));
}
if (_query.getOperation() == QueryOperations.OP_UPDATE) {
- // handle which types of parameters we are using, if any
- if (_positional != null)
- return asInt(_query.updateAll(_positional));
- if (_named != null)
- return asInt(_query.updateAll(_named));
- return asInt(_query.updateAll());
+ return asInt(paramValues.isEmpty() ? _query.updateAll() : _query.updateAll(paramValues));
}
- throw new InvalidStateException(_loc.get("not-update-delete-query",
- _query.getQueryString()), null, null, false);
+ throw new InvalidStateException(_loc.get("not-update-delete-query", getQueryString()), null, null, false);
}
/**
@@ -372,7 +376,6 @@
/**
* Converts the given Date to a value corresponding to given temporal type.
*/
-
Object convertTemporalType(Date value, TemporalType type) {
switch (type) {
case DATE:
@@ -390,69 +393,116 @@
return convertTemporalType(value.getTime(), type);
}
- public OpenJPAQuery setParameter(int position, Object value) {
+ /**
+ * Bind an argument to a positional parameter.
+ * @param position
+ * @param value
+ * @return the same query instance
+ * @throws IllegalArgumentException if position does not correspond to a positional
+ * parameter of the query or if the argument is of incorrect type
+ */
+ public OpenJPAQuery<X> setParameter(int position, Object value) {
_query.assertOpen();
_em.assertNotCloseInvoked();
_query.lock();
try {
+ // native queries are not parsed and hence their parameter types are not known
+ if (!isNative() && !getDeclaredParameterKeys().contains(position)) {
+ throw new IllegalArgumentException(_loc.get("param-missing-pos",
+ position, getQueryString(), getDeclaredParameterKeys()).getMessage());
+ }
if (isNative() && position < 1) {
throw new IllegalArgumentException(_loc.get("bad-pos-params",
- position, _query.getQueryString()).toString());
+ position, getQueryString()).toString());
}
- // not allowed to mix positional and named parameters (EDR2 3.6.4)
- if (_named != null)
- throw new InvalidStateException(_loc.get(
- "no-pos-named-params-mix", _query.getQueryString()),
- null, null, false);
if (position < 1)
throw new InvalidStateException(_loc.get("illegal-index",
position), null, null, false);
- if (_positional == null)
- _positional = new TreeMap<Integer, Object>();
+ Class<?> valueType = (Class<?>)_query.getParameterTypes().get((Object)position);
+ ParameterImpl<?> param = new ParameterImpl<Object>(position, valueType);
+ registerParameter(param);
+ param.bindValue(value);
- _positional.put(position, value);
return this;
} finally {
_query.unlock();
}
}
- public OpenJPAQuery setParameter(String name, Calendar value,
+ public OpenJPAQuery<X> setParameter(String name, Calendar value,
TemporalType type) {
return setParameter(name, convertTemporalType(value, type));
}
- public OpenJPAQuery setParameter(String name, Date value, TemporalType type)
- {
+ public OpenJPAQuery<X> setParameter(String name, Date value, TemporalType type) {
return setParameter(name, convertTemporalType(value, type));
}
- public OpenJPAQuery setParameter(String name, Object value) {
+ /**
+ * Sets the parameter of the given name to the given value.
+ */
+ public OpenJPAQuery<X> setParameter(String name, Object value) {
_query.assertOpen();
_em.assertNotCloseInvoked();
_query.lock();
try {
+ // native queries are not parsed and hence their parameter types are not known
+ if (!isNative() && !getDeclaredParameterKeys().contains(name)) {
+ throw new IllegalArgumentException(_loc.get("param-missing-name",
+ name, getQueryString(), getDeclaredParameterKeys()).getMessage());
+ }
if (isNative()) {
throw new IllegalArgumentException(_loc.get("no-named-params",
- name, _query.getQueryString()).toString());
+ name, getQueryString()).toString());
}
- // not allowed to mix positional and named parameters (EDR2 3.6.4)
- if (_positional != null)
- throw new InvalidStateException(_loc.get(
- "no-pos-named-params-mix", _query.getQueryString()),
- null, null, false);
-
- if (_named == null)
- _named = new HashMap();
- _named.put(name, value);
+
+ Class<?> valueType = (Class<?>)_query.getParameterTypes().get(name);
+ ParameterImpl<?> param = new ParameterImpl<Object>(name, valueType);
+ registerParameter(param);
+ param.bindValue(value);
+
return this;
} finally {
_query.unlock();
}
}
+ /**
+ * Registers a parameter by creating an entry in the named or positional parameter map.
+ * The named or positional parameter map may be created if this is the first parameter
+ * to be registered.
+ * It is not permitted to mix named and positional parameter. So one of them is always
+ * null.
+ *
+ * @exception IllegalStateException if a positional parameter is given when named parameters
+ * had been registered or vice versa.
+ */
+ QueryImpl<X> registerParameter(QueryParameter<?> param) {
+ if (param.isNamed()) {
+ if (_positional != null)
+ throw new IllegalStateException(_loc.get("param-pos-named-mix", param, _query.getQueryString(),
+ _positional.keySet()).getMessage());
+ if (_named == null) {
+ _named = new HashMap<String, QueryParameter<?>>();
+ }
+ _named.put(param.getName(), param);
+ } else if (param.isPositional()) {
+ if (_named != null)
+ throw new IllegalStateException(_loc.get("param-pos-named-mix", param, _query.getQueryString(),
+ _named.keySet()).getMessage());
+ if (_positional == null) {
+ _positional = new TreeMap<Integer, QueryParameter<?>>();
+ }
+ _positional.put(param.getPosition(), param);
+ } else {
+ throw new IllegalStateException(_loc.get("param-no-key", param).getMessage());
+ }
+
+ return this;
+ }
+
public boolean isNative() {
return QueryLanguages.LANG_SQL.equals(getLanguage());
}
@@ -462,22 +512,42 @@
}
/**
- * Gets the array of positional parameter values. A value of
- * <code>GAP_FILLER</code> indicates that user has not set the
- * corresponding positional parameter. A value of null implies that user has
- * set the value as null.
+ * Gets the array of positional parameter values.
+ * The n-th array element represents (n+1)-th positional parameter.
+ * If a parameter has been declared but not bound to a value then
+ * the value is null and hence is indistinguishable from the value
+ * being actually null.
+ * If the parameter indexing is not contiguous then the unspecified
+ * parameters are considered as null.
*/
public Object[] getPositionalParameters() {
_query.lock();
try {
- return (_positional == null) ? EMPTY_ARRAY :
- _positional.values().toArray();
+ if (_positional == null)
+ return EMPTY_ARRAY;
+ Object[] result = new Object[calculateMaxKey(_positional.keySet())];
+ for (Map.Entry<Integer, QueryParameter<?>> e : _positional.entrySet()) {
+ result[e.getKey().intValue()-1] = e.getValue().getValue();
+ }
+ return result;
} finally {
_query.unlock();
}
}
+
+ /**
+ * Calculate the maximum value of the given set.
+ */
+ int calculateMaxKey(Set<Integer> p) {
+ if (p == null)
+ return 0;
+ int max = Integer.MIN_VALUE;
+ for (Integer i : p)
+ max = Math.max(max, i);
+ return max;
+ }
- public OpenJPAQuery setParameters(Object... params) {
+ public OpenJPAQuery<X> setParameters(Object... params) {
_query.assertOpen();
_em.assertNotCloseInvoked();
_query.lock();
@@ -493,17 +563,28 @@
}
}
+ /**
+ * Gets the value of all the named parameters.
+ * If a parameter has been declared but not bound to a value then
+ * the value is null and hence is indistinguishable from the value
+ * being actually null.
+ */
public Map<String, Object> getNamedParameters() {
_query.lock();
try {
- return (_named == null) ? Collections.EMPTY_MAP : Collections
- .unmodifiableMap(_named);
+ if (_named == null)
+ return Collections.EMPTY_MAP;
+ Map<String, Object> result = new HashMap<String, Object>();
+ for (Map.Entry<String, QueryParameter<?>> e : _named.entrySet()) {
+ result.put(e.getKey(), e.getValue().getValue());
+ }
+ return result;
} finally {
_query.unlock();
}
}
- public OpenJPAQuery setParameters(Map params) {
+ public OpenJPAQuery<X> setParameters(Map params) {
_query.assertOpen();
_em.assertNotCloseInvoked();
_query.lock();
@@ -519,7 +600,7 @@
}
}
- public OpenJPAQuery closeAll() {
+ public OpenJPAQuery<X> closeAll() {
_query.closeAll();
return this;
}
@@ -558,7 +639,7 @@
return _hintHandler.getHints();
}
- public OpenJPAQuery setHint(String key, Object value) {
+ public OpenJPAQuery<X> setHint(String key, Object value) {
_em.assertNotCloseInvoked();
_hintHandler.setHint(key, value);
return this;
@@ -684,6 +765,7 @@
_query = new DelegatingQuery(newQuery, _em.getExceptionTranslator());
}
+ // package protected
QueryImpl setId(String id) {
_id = id;
return this;
@@ -699,24 +781,42 @@
_lock.unlock();
}
- public <T> Parameter<T> getParameter(String arg0, Class<T> arg1) {
- throw new UnsupportedOperationException(
- "JPA 2.0 - Method not yet implemented");
+ public <T> Parameter<T> getParameter(String name, Class<T> arg1) {
+ return (Parameter<T>)_named.get(name);
}
- public <T> Parameter<T> getParameter(int arg0, Class<T> arg1) {
- throw new UnsupportedOperationException(
- "JPA 2.0 - Method not yet implemented");
+ public <T> Parameter<T> getParameter(int pos, Class<T> arg1) {
+ return (Parameter<T>)_positional.get(pos);
}
- public <T> T getParameterValue(Parameter<T> arg0) {
- throw new UnsupportedOperationException(
- "JPA 2.0 - Method not yet implemented");
+ /**
+ * Return the value bound to the parameter.
+ * @param param parameter object
+ * @return parameter value
+ * @throws IllegalStateException if the parameter has not been been bound
+ * @throws IllegalArgumentException if the parameter does not belong to this query
+ */
+ public <T> T getParameterValue(Parameter<T> p) {
+ if ((_named == null || !_named.containsValue(p))
+ && (_positional == null || !_positional.containsValue(p))) {
+ throw new IllegalArgumentException(_loc.get("param-missing", p, getQueryString(),
+ getBoundParameterKeys()).getMessage());
+ }
+ QueryParameter<T> param = (QueryParameter<T>)p;
+ return (T)param.getValue(true);
}
+ /**
+ * Gets the parameters registered for this query.
+ */
public Set<Parameter<?>> getParameters() {
- throw new UnsupportedOperationException(
- "JPA 2.0 - Method not yet implemented");
+ Set<Parameter<?>> result = new HashSet<Parameter<?>>();
+ if (_named != null) {
+ result.addAll(_named.values());
+ } else if (_positional != null) {
+ result.addAll(_positional.values());
+ }
+ return result;
}
public <T> ResultItem<T> getResultItem(String arg0, Class<T> arg1) {
@@ -744,40 +844,85 @@
"JPA 2.0 - Method not yet implemented");
}
- public <T> TypedQuery<X> setParameter(Parameter<T> param, T arg1) {
- throw new UnsupportedOperationException(
- "JPA 2.0 - Method not yet implemented");
+ public <T> OpenJPAQuery<X> setParameter(Parameter<T> p, T arg1) {
+ QueryParameter<T> param = (QueryParameter<T>)p;
+ param.bindValue(arg1);
+ return this;
}
- public TypedQuery<X> setParameter(Parameter<Date> arg0, Date arg1,
- TemporalType arg2) {
- // TODO Auto-generated method stub
- return null;
+ public OpenJPAQuery<X> setParameter(Parameter<Date> p, Date date, TemporalType type) {
+ return setParameter(p, (Date)convertTemporalType(date, type));
}
- public TypedQuery<X> setParameter(Parameter<Calendar> arg0, Calendar arg1,
- TemporalType arg2) {
- // TODO Auto-generated method stub
- return null;
+ public TypedQuery<X> setParameter(Parameter<Calendar> p, Calendar cal, TemporalType type) {
+ return setParameter(p, (Calendar)convertTemporalType(cal, type));
}
- public Parameter<?> getParameter(String arg0) {
- // TODO Auto-generated method stub
- return null;
+ public QueryParameter<?> getParameter(String name) {
+ if (_named == null || !_named.containsKey(name))
+ throw new IllegalArgumentException(_loc.get("param-missing-name",
+ name, getQueryString(), getBoundParameterKeys()).getMessage());
+ return _named.get(name);
}
- public Parameter<?> getParameter(int arg0) {
- // TODO Auto-generated method stub
- return null;
+ /**
+ * Get the positional parameter with the given position.
+ *
+ * @param position specified in the user query.
+ * @return parameter object
+ * @throws IllegalArgumentException if the parameter with the given position does not exist
+ */
+ public QueryParameter<?> getParameter(int pos) {
+ if (_positional == null || !_positional.containsKey(pos))
+ throw new IllegalArgumentException(_loc.get("param-missing-pos",
+ pos, getQueryString(), getBoundParameterKeys()).getMessage());
+ return _positional.get(pos);
}
- public Object getParameterValue(String arg0) {
- // TODO Auto-generated method stub
- return null;
+ /**
+ * Return the value bound to the parameter.
+ *
+ * @param name name of the parameter
+ * @return parameter value
+ *
+ * @throws IllegalStateException if this parameter has not been bound
+ */
+ public Object getParameterValue(String name) {
+ return getParameter(name).getValue(true);
}
- public Object getParameterValue(int arg0) {
- // TODO Auto-generated method stub
- return null;
+ /**
+ * Return the value bound to the parameter.
+ *
+ * @param pos position of the parameter
+ * @return parameter value
+ *
+ * @throws IllegalStateException if this parameter has not been bound
+ */
+ public Object getParameterValue(int pos) {
+ return getParameter(pos).getValue(true);
+ }
+
+ /**
+ * Gets the parameter keys bound with this query.
+ */
+ public Set<?> getBoundParameterKeys() {
+ if (_named != null)
+ return _named.keySet();
+ if (_positional != null)
+ return _positional.keySet();
+ return Collections.EMPTY_SET;
+ }
+
+ /**
+ * Gets the declared parameter keys in the given query.
+ * This information is only available after the query has been parsed.
+ * As native language queries are not parsed, this information is not available for them.
+ *
+ * @return set of parameter identifiers in a parsed query
+ */
+ public Set<?> getDeclaredParameterKeys() {
+ return _query.getParameterTypes().keySet();
}
+
}
Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryParameter.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryParameter.java?rev=796931&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryParameter.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryParameter.java Thu Jul 23 02:47:11 2009
@@ -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;
+
+import javax.persistence.Parameter;
+
+/**
+ * A parameter for a query.
+ *
+ * @author Pinaki Poddar
+ * @since 2.0.0
+ *
+ * @param <T> the type of value that can be bound to this parameter.
+ */
+public interface QueryParameter<T> extends Parameter<T> {
+ /**
+ * Affirms if this parameter key is a String.
+ */
+ public abstract boolean isNamed();
+
+ /**
+ * Affirms if this parameter key is a integer.
+ */
+ public abstract boolean isPositional();
+
+ /**
+ * Affirms if this parameter can be set to the given value.
+ */
+ public abstract boolean isValueAssignable(Object v);
+
+ /**
+ * Affirms if a value has been bound to this parameter.
+ */
+ public abstract boolean isBound();
+
+ /**
+ * Binds the given value to this parameter.
+ */
+ public abstract QueryParameter<T> bindValue(Object v);
+
+ /**
+ * Gets the value of this parameter without checking whether the any value has been
+ * bound. Hence it can not be distinguished whether the value of a parameter is
+ * explicitly set to null or may not been set at all.
+ * To distinguish between these two cases,
+ * @see #getValue(boolean)
+ *
+ * @return the current value.
+ */
+ public abstract Object getValue();
+
+ /**
+ * Gets the value of this parameter.
+ * The value of a parameter can be explicitly set to null or may not been set at all.
+ * To distinguish between these two cases, either check whether a value is bound
+ * {@linkplain #isBound()} prior to this call or use the boolean argument to make
+ * this check.
+ *
+ * @param mustBeBound if true then exception is raised if no value is bound to this parameter.
+ * Otherwise, the current value is returned without any check.
+ *
+ * @return the current value.
+ */
+ public abstract Object getValue(boolean mustBeBound);
+
+ /**
+ * Clears the bound value, if any.
+ */
+ public abstract void clearBinding();
+
+ /**
+ * Gets the type of the value expected to be bound to this parameter.
+ */
+ public abstract Class<?> getExpectedValueType();
+
+}
Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryParameter.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java Thu Jul 23 02:47:11 2009
@@ -27,7 +27,6 @@
import java.util.Map;
import java.util.Set;
-import javax.persistence.Parameter;
import javax.persistence.Tuple;
import javax.persistence.criteria.CompoundSelection;
import javax.persistence.criteria.CriteriaQuery;
@@ -71,7 +70,7 @@
public QueryExpressions eval(Object parsed, ExpressionStoreQuery query,
ExpressionFactory factory, ClassMetaData candidate) {
- CriteriaQueryImpl c = (CriteriaQueryImpl) parsed;
+ CriteriaQueryImpl<?> c = (CriteriaQueryImpl<?>) parsed;
return c.getQueryExpressions(factory);
}
@@ -83,9 +82,9 @@
public String getLanguage() {
return LANG_CRITERIA;
}
+
/**
- * Create a Criteria query object with the specified result
- * type.
+ * Create a Criteria query object with the specified result type.
* @param resultClass type of the query result
* @return query object
*/
@@ -504,13 +503,21 @@
return new PredicateImpl.Or(x,y);
}
+ /**
+ * Construct a ParameterExpression with a null name as key.
+ * The name of this parameter will be assigned automatically
+ * when this parameter expression is
+ * {@linkplain CriteriaQueryImpl#registerParameter(ParameterExpressionImpl)
+ * registered} in a Criteriaquery during tree traversal.
+ *
+ * @see ParameterExpressionImpl#assignAutoName(String)
+ */
public <T> ParameterExpression<T> parameter(Class<T> paramClass) {
- throw new UnsupportedOperationException("Unnamed parameter " +
- "not supported for CriteriaQuery");
+ return new ParameterExpressionImpl<T>(paramClass, null);
}
public <T> ParameterExpression<T> parameter(Class<T> paramClass, String name) {
- return new ParameterImpl<T>(paramClass, name);
+ return new ParameterExpressionImpl<T>(paramClass, name);
}
public <N extends Number> Expression<N> prod(Expression<? extends N> x, Expression<? extends N> y) {
@@ -667,7 +674,7 @@
public CompoundSelection<Object[]> array(Selection<?>... arg0) {
// TODO Auto-generated method stub
- return null;
+ throw new AbstractMethodError();
}
public Predicate isNotNull(Expression<?> x) {
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java Thu Jul 23 02:47:11 2009
@@ -60,7 +60,6 @@
evalAccessPaths(exps, factory, q);
//exps.alias = null; // String
- exps.ascending = new boolean[]{false};
evalDistinct(exps, factory, q);
evalFetchJoin(exps, factory, q);
evalCrossJoinRoots(exps, factory, q);
@@ -114,10 +113,8 @@
CriteriaQueryImpl<?> q) {
List<Order> orders = q.getOrderList();
MetamodelImpl model = q.getMetamodel();
- if (orders == null)
- return null;
+ int ordercount = (orders == null) ? 0 : orders.size();
Map<Expression<?>, Value> exp2Vals = new HashMap<Expression<?>, Value>();
- int ordercount = orders.size();
exps.ordering = new Value[ordercount];
exps.orderingClauses = new String[ordercount];
exps.orderingAliases = new String[ordercount];
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java Thu Jul 23 02:47:11 2009
@@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -66,7 +67,7 @@
private Set<Root<?>> _roots;
private PredicateImpl _where;
private List<Order> _orders;
- private LinkedHashMap<ParameterExpression<?>, Class<?>> _paramTypes;
+ private LinkedHashMap<ParameterExpression<?>, Class<?>> _paramTypes;
private List<Selection<?>> _selections;
private List<Expression<?>> _groups;
private PredicateImpl _having;
@@ -79,11 +80,13 @@
private int aliasCount = 0;
private static String ALIAS_BASE = "autoAlias";
- private Map<Selection<?>,Value> _variables =
- new HashMap<Selection<?>, Value>();
- private Map<Selection<?>,Value> _values =
- new HashMap<Selection<?>, Value>();
- private Map<Selection<?>,String> _aliases = null;
+ // Auto-generated Parameter name
+ private int autoParameterCount = 0;
+ private static String PARAM_BASE = "autoParam";
+
+ private Map<Selection<?>,Value> _variables = new HashMap<Selection<?>, Value>();
+ private Map<Selection<?>,Value> _values = new HashMap<Selection<?>, Value>();
+ private Map<Selection<?>,String> _aliases = null;
private Map<Selection<?>,Value> _rootVariables =
new HashMap<Selection<?>, Value>();
@@ -183,20 +186,21 @@
/**
* Registers the given parameter.
+ * On registration, an unnamed parameter is assigned an auto-generated
+ * name.
*
- * @param p
*/
- public void registerParameter(ParameterImpl<?> p) {
+ public void registerParameter(ParameterExpressionImpl<?> p) {
if (_paramTypes == null) {
_paramTypes = new LinkedHashMap<ParameterExpression<?>, Class<?>>();
}
_paramTypes.put(p, p.getJavaType());
- if (p.getPosition() == null)
- p.setPosition(_paramTypes.size());
+ if (p.getName() == null)
+ p.assignAutoName(PARAM_BASE + (++autoParameterCount));
}
public Set<ParameterExpression<?>> getParameters() {
- return _paramTypes.keySet();
+ return _paramTypes == null ? Collections.EMPTY_SET : _paramTypes.keySet();
}
/**
@@ -317,6 +321,10 @@
return subquery;
}
+ /**
+ * Return map of <String, Class> where key is the name of the parameter
+ * and value is the expected type.
+ */
public LinkedMap getParameterTypes() {
if (_paramTypes == null)
return StoreQuery.EMPTY_PARAMS;
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java Thu Jul 23 02:47:11 2009
@@ -40,14 +40,9 @@
public abstract class ExpressionImpl<X> extends SelectionImpl<X>
implements Expression<X> {
- abstract Value toValue(ExpressionFactory factory, MetamodelImpl model,
- CriteriaQueryImpl<?> q);
-// {
-// throw new AbstractMethodError(this.getClass().getName());
-// }
+ abstract Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl<?> q);
- org.apache.openjpa.kernel.exps.Expression toKernelExpression(
- ExpressionFactory factory, MetamodelImpl model,
+ org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, MetamodelImpl model,
CriteriaQueryImpl<?> q) {
throw new AbstractMethodError(this.getClass().getName());
}
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java Thu Jul 23 02:47:11 2009
@@ -697,8 +697,8 @@
public Value toValue(ExpressionFactory factory, MetamodelImpl model,
CriteriaQueryImpl<?> q) {
Object value = arg;
- if (arg instanceof ParameterImpl) {
- return ((ParameterImpl)arg).toValue(factory, model, q);
+ if (arg instanceof ParameterExpressionImpl) {
+ return ((ParameterExpressionImpl)arg).toValue(factory, model, q);
}
int literalType = Literal.TYPE_UNKNOWN;
if (arg != null) {
Copied: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java (from r792583, openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java)
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java?p2=openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java&p1=openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java&r1=792583&r2=796931&rev=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java Thu Jul 23 02:47:11 2009
@@ -19,73 +19,143 @@
package org.apache.openjpa.persistence.criteria;
import java.util.Collection;
-import java.util.List;
-import javax.persistence.Parameter;
import javax.persistence.criteria.ParameterExpression;
-import javax.persistence.criteria.Selection;
import org.apache.openjpa.kernel.exps.ExpressionFactory;
import org.apache.openjpa.kernel.exps.Value;
import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.persistence.ParameterImpl;
+import org.apache.openjpa.persistence.QueryParameter;
import org.apache.openjpa.persistence.meta.MetamodelImpl;
+import org.apache.openjpa.util.InternalException;
/**
* Parameter of a criteria query.
+ * <br>
+ * A parameter in CriteriaQuery is always a named parameter but
+ * can be constructed without a name.
+ * Positional parameters are not allowed in CriteraQuery.
+ * The unnamed Parameter will be assigned a name automatically
+ * when they are registered to a CriteriaQuery.
+ * <br>
+ * This expression uses a delegate Parameter implementation because
+ * multiple inheritance is not allowed in Java language.
*
* @author Pinaki Poddar
* @author Fay wang
*
* @param <T> the type of value held by this parameter.
*/
-public class ParameterImpl<T> extends ExpressionImpl<T> implements ParameterExpression<T> {
- private String name;
- private Integer position;
+public class ParameterExpressionImpl<T> extends ExpressionImpl<T>
+ implements ParameterExpression<T>, QueryParameter<T> {
+
+ private String _autoName = null;
+ private final ParameterImpl<T> _delegate;
- public ParameterImpl(Class<T> cls, String name) {
+ /**
+ * Construct a Parameter of given expected value type and name.
+ *
+ * @param cls expected value type
+ * @param name name of the parameter which can be null.
+ */
+ public ParameterExpressionImpl(Class<T> cls, String name) {
super(cls);
- this.name = name;
+ _delegate = new ParameterImpl<T>(name, cls);
}
- public final String getName() {
- return name;
- }
-
- public Integer getPosition() {
- return position;
+ /**
+ * Gets the name of this parameter.
+ * The name can either be assigned by the user or automatically
+ * generated by the implementation.
+ *
+ * @see #assignAutoName(String)
+ */
+ public final String getName() {
+ return _autoName != null ? _autoName : _delegate.getName();
}
- public void setPosition(int p) {
- position = p;
+ /**
+ * Assigns an automatically generated name to this parameter.
+ * Package protected for internal use only.
+ *
+ * @exception if this parameter has been given a non-null
+ * name at construction.
+ */
+ final void assignAutoName(String auto) {
+ if (_delegate.getName() != null)
+ throw new InternalException("Can not assign name [" + auto + "] to " + this);
+ _autoName = auto;
}
+ /**
+ * Raises an internal exception because parameters of CriteriaQuery
+ * are not positional.
+ */
+ public final Integer getPosition() {
+ throw new InternalException(this + " must not be asked for its position");
+ }
+
+ public final void clearBinding() {
+ _delegate.clearBinding();
+ }
+
+ public final QueryParameter<T> bindValue(Object v) {
+ return _delegate.bindValue(v);
+ }
+
+ public Class<?> getExpectedValueType() {
+ return _delegate.getExpectedValueType();
+ }
+
+ public final T getValue() {
+ return (T)_delegate.getValue();
+ }
+
+ public final Object getValue(boolean mustBeBound) {
+ return _delegate.getValue(mustBeBound);
+ }
+
+ public final boolean isBound() {
+ return _delegate.isBound();
+ }
+
+ public final boolean isNamed() {
+ return true;
+ }
+
+ public final boolean isPositional() {
+ return false;
+ }
+
+ public final boolean isValueAssignable(Object v) {
+ return _delegate.isValueAssignable(v);
+ }
+
+ public String toString() {
+ StringBuilder buf = new StringBuilder("ParameterExpression");
+ buf.append("<" + (getExpectedValueType() == null ? "?" : getExpectedValueType().getName()) + ">");
+ buf.append("("+getName()+":");
+ buf.append((isBound() ? getValue() : "UNBOUND") + ")");
+
+ return buf.toString();
+ }
+
@Override
- public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl<?> q) {
+ public Value toValue(ExpressionFactory factory, MetamodelImpl model, CriteriaQueryImpl<?> q) {
q.registerParameter(this);
ClassMetaData meta = null;
Class<?> clzz = getJavaType();
- Object paramKey = getKey();
- int index = getIndex();
+ Object paramKey = getName();
+ if (paramKey == null)
+ throw new InternalException(this + " should have been assigned a name");
boolean isCollectionValued = Collection.class.isAssignableFrom(clzz);
org.apache.openjpa.kernel.exps.Parameter param = isCollectionValued
? factory.newCollectionValuedParameter(paramKey, clzz)
: factory.newParameter(paramKey, clzz);
param.setMetaData(meta);
- param.setIndex(index);
return param;
- }
-
- Object getKey() {
- if (name == null && position == null)
- throw new IllegalStateException(this + " key is not set");
- return name != null ? name : position;
- }
-
- int getIndex() {
- if (position == null)
- throw new IllegalStateException(this + " index is not set");
- return position-1;
- }
+ }
}
Modified: openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties?rev=796931&r1=796930&r2=796931&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties (original)
+++ openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties Thu Jul 23 02:47:11 2009
@@ -78,8 +78,6 @@
not-select-query: Cannot perform a select on update or delete query: "{0}".
no-results: Query did not return any results: "{0}".
mult-results: Query returned multiple results: "{0}".
-no-pos-named-params-mix: Cannot mix named and positional parameters in query \
- "{0}".
bad-query-hint: "{0}" is not a supported query hint. May be you meant "{1}"?
bad-query-hint-value: Invalid value specified for query hint "{0}": {1}
detached: Cannot perform this operation on detached entity "{0}".
@@ -109,8 +107,6 @@
ser-query: Writing query "{1}".
ser-sequence: Writing sequence "{0}".
no-sql: You must provide a SQL string when creating a native query.
-no-named-params: Named parameter "{0}" is invalid for native query "{1}". \
- Use only 1-based positional parameter in native queries.
bad-pos-params: Positional parameter "{0}" is invalid for native query "{1}". \
Use only 1-based positional parameter in native queries.
bad-param-type: The parameter "{1}" in query "{0}" is set to a value of type \
@@ -198,6 +194,28 @@
loaded by the JVM.
vlem-creation-info: OpenJPA dynamically loaded a validation provider.
no-embeddable-metadata: Unable to load metadata for embeddable class "{0}".
+<<<<<<< .mine
+
+param-missing: {0} is not declared in query "{1}". \
+ Declared parameter keys are "{2}".
+param-missing-pos: Parameter position {0} is not declared in query "{1}". \
+ Declared parameter keys are "{2}".
+param-missing-name: Parameter named "{0}" is not declared in query "{1}". \
+ Declared parameter keys are "{2}".
+param-pos-in-criteria: Can not set value for positional parameter {0} \
+ because the executable query is created by a Criteria Query. \
+ Use only named parameter or parameter expressions to set values \
+ for Criteria Query parameters.
+params-named-in-native: Can not set value for named parameter "{0}" \
+ because the executable query is created by a native query "{1}". \
+ Use only 1-based positional parameter to set values \in native queries.
+param-null-assignable: {0} can not be assigned to null.
+param-value-not-assignable: {0} can not be assigned to "{1}" of {2}.
+param-not-bound: {0} is not bound to any value.
+param-pos-named-mix: {0} can not be used in query " {1}" because JPA does \
+ not allow to mix named and positional parameters in a query. Existing \
+ parameters are "{2}".
+param-no-key: {0} has either a name nor a position as identifier.
tuple-element-not-found: TupleElement "{0}" "{1}" was not found in this Tuple. Contents of the Tuple: {2}.
tuple-was-null: Input argument {0} was null. Unable to proceed.
tuple-element-wrong-type: TupleElement type did not match for {0} "{1}". Provided type "{2}" , actual type "{3}"