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}"