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 2008/08/02 15:58:57 UTC

svn commit: r681977 - 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/jdbc/query/cache/ openjpa-persistence-jdbc/src/test/java/or...

Author: ppoddar
Date: Sat Aug  2 06:58:56 2008
New Revision: 681977

URL: http://svn.apache.org/viewvc?rev=681977&view=rev
Log:
OPENJPA-497: TemporalType conversion at facade level Query.
Also includes extensive changes in parameter validation logic and data structure.

Added:
    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/jdbc/query/domain/Binder.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/TimeKeeper.java
Modified:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/TestNonPrimaryKeyQueryParameters.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestDupNamedQuery.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
    openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties

Added: 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=681977&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestQueryParameterBinding.java Sat Aug  2 06:58:56 2008
@@ -0,0 +1,247 @@
+/*
+ * 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.jdbc.query;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+import org.apache.openjpa.persistence.ArgumentException;
+import org.apache.openjpa.persistence.jdbc.query.domain.Binder;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Tests validation of positional and named parameter binding for JPQL queries.
+ *  
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class TestQueryParameterBinding extends SingleEMFTestCase {
+	private static String JPQL = "SELECT p FROM Binder p ";
+	
+	private static int INT_VALUE    = 1;
+	private static String STR_VALUE = "2";
+	private static double DBL_VALUE = 3.0;
+	
+	private EntityManager em;
+	@Override
+	public void setUp() throws Exception {
+		super.setUp(CLEAR_TABLES, Binder.class);
+		
+		em = emf.createEntityManager();
+		em.getTransaction().begin();
+		em.persist(new Binder(INT_VALUE, STR_VALUE, DBL_VALUE));
+		em.getTransaction().commit();
+	}
+	
+	public void testPositionalParameterWithPositionalBindingSucceeds() {
+		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, STR_VALUE);
+		q.setParameter(3, DBL_VALUE);
+		
+		assertEquals(1, q.getResultList().size());
+	}
+	
+	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);
+	}
+	
+	public void testPositionalParameterWithInsufficientValuesFails() {
+		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, STR_VALUE);
+		
+		fail(q);
+	}
+	
+	public void testPositionalParameterWithExtraValuesFails() {
+		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, STR_VALUE);
+		q.setParameter(3, DBL_VALUE);
+		q.setParameter(4, 4);
+		
+		fail(q);
+	}
+
+	public void testPositionalParameterWithRepeatedValuesSucceeds() {
+		String jPQL_POSITIONAL_REPEATED_PARAM  = 
+			JPQL + "WHERE p.p1=?1 OR p.p1=?1 AND p.p3=?2";
+		Query q = em.createQuery(jPQL_POSITIONAL_REPEATED_PARAM);
+		q.setParameter(1,  INT_VALUE);
+		q.setParameter(2,  DBL_VALUE);
+		
+		assertEquals(1,q.getResultList().size());
+	}
+	
+	public void testPositionalParameterWithGapSucceeds() {
+		String JPQL_POSITIONAL_GAP_IN_PARAM  = 
+			JPQL + "WHERE p.p1=?1 AND p.p2=?3";
+		Query q = em.createQuery(JPQL_POSITIONAL_GAP_IN_PARAM);
+		q.setParameter(1,  INT_VALUE);
+		q.setParameter(3,  STR_VALUE);
+		
+		assertEquals(1,q.getResultList().size());
+	}
+	
+	public void testPositionalParameterWithGapFails() {
+		String JPQL_POSITIONAL_GAP_IN_PARAM  = 
+			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);
+		
+		fail(q);
+	}
+	
+	public void testNamedParameterWithNamedBindingSucceeds() {
+		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", STR_VALUE);
+		q.setParameter("p3", DBL_VALUE);
+		
+		assertEquals(1, q.getResultList().size());
+	}
+	
+	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);
+	}
+	
+	public void testNamedParameterWithInsufficientValuesFails() {
+		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", STR_VALUE);
+		
+		fail(q);
+	}
+	
+	public void testNamedParameterWithExtraValuesFails() {
+		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", STR_VALUE);
+		q.setParameter("p3", DBL_VALUE);
+		q.setParameter("p4", 4);
+		
+		fail(q);
+	}
+
+	public void testNamedParameterWithRepeatedValuesSucceeds() {
+		String jPQL_NAMED_REPEATED_PARAM  = 
+			JPQL + "WHERE p.p1=:p1 OR p.p1=:p1 AND p.p3=:p2";
+		Query q = em.createQuery(jPQL_NAMED_REPEATED_PARAM);
+		q.setParameter("p1",  INT_VALUE);
+		q.setParameter("p2",  DBL_VALUE);
+		
+		assertEquals(1,q.getResultList().size());
+	}
+	
+	public void testNamedParameterWithGapSucceeds() {
+		String JPQL_NAMED_GAP_IN_PARAM  = 
+			JPQL + "WHERE p.p1=:p1 AND p.p2=:p3";
+		Query q = em.createQuery(JPQL_NAMED_GAP_IN_PARAM);
+		q.setParameter("p1",  INT_VALUE);
+		q.setParameter("p3",  STR_VALUE);
+		
+		assertEquals(1,q.getResultList().size());
+	}
+	
+	public void testNamedParameterWithGapFails() {
+		String JPQL_NAMED_GAP_IN_PARAM  = 
+			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);
+	}
+	
+	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);
+	}
+	
+	public void testPositionalParameterWithWrongType() {
+		String JPQL_NAMED  = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3";
+		Query q = em.createQuery(JPQL_NAMED);
+		q.setParameter(1,  INT_VALUE);
+		q.setParameter(2,  DBL_VALUE);
+		q.setParameter(3,  STR_VALUE);
+		
+		fail(q);
+	}
+	
+	public void testNamedParameterWithNullValue() {
+		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",  null);
+		q.setParameter("p3",  null);
+		
+		fail(q);
+	}
+	
+	public void testPositionalParameterWithNullValue() {
+		String JPQL_NAMED  = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3";
+		Query q = em.createQuery(JPQL_NAMED);
+		q.setParameter(1,  INT_VALUE);
+		q.setParameter(2,  null);
+		q.setParameter(3,  null);
+		
+		fail(q);
+	}
+	
+	
+	void fail(Query q) {
+		try {
+			q.getResultList();
+			fail("Expeceted " + ArgumentException.class.getName());
+		} catch (IllegalArgumentException ex) {
+		// good
+			System.err.println("*** ERROR " + getName());
+			System.err.println("*** ERROR " + ex.getMessage());
+		}
+	}
+	
+}

Added: 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=681977&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestTemporalTypeQueryParameterBinding.java Sat Aug  2 06:58:56 2008
@@ -0,0 +1,198 @@
+/*
+ * 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.jdbc.query;
+
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import javax.persistence.TemporalType;
+
+import org.apache.openjpa.persistence.ArgumentException;
+import org.apache.openjpa.persistence.jdbc.query.domain.TimeKeeper;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Tests that queries can convert to temporal types.
+ * Also tests that parameter validation for mismatch between named parameter
+ * and positional binding or vice versa.
+ *  
+ * Originally reported in 
+ * <A HRE="http://issues.apache.org/jira/browse/OPENJPA-112>OPENJPA-497</A>
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class TestTemporalTypeQueryParameterBinding extends SingleEMFTestCase {
+	private static Calendar PARAM_CALENDAR = Calendar.getInstance();
+	private  static long T1 = PARAM_CALENDAR.getTimeInMillis();
+	private  static long T2 = T1 + 2000; 
+	private  static long T3 = T1 + 3000;
+	
+	private static Date     VALUE_DATE     = new Date(T1);
+	private static Time     VALUE_TIME     = new Time(T2);
+	private static Timestamp VALUE_TSTAMP   = new Timestamp(T3);
+	
+	
+	private static String JPQL_NAMED  = 
+		"SELECT p FROM TimeKeeper p WHERE p.date=:d AND p.time=:t AND p.tstamp=:ts";
+	private static String JPQL_POSITIONAL  = 
+		"SELECT p FROM TimeKeeper p WHERE p.date=?1 AND p.time=?2 AND p.tstamp=?3";
+	
+	private EntityManager em;
+	@Override
+	public void setUp() throws Exception {
+		super.setUp(CLEAR_TABLES, TimeKeeper.class);
+		em = emf.createEntityManager();
+		
+		TimeKeeper pc = new TimeKeeper();
+		pc.setDate(VALUE_DATE);
+		pc.setTime(VALUE_TIME);
+		pc.setTstamp(VALUE_TSTAMP);
+		
+		em.getTransaction().begin();
+		em.persist(pc);
+		em.getTransaction().commit();
+	}
+	
+	public void testNamedParameterConvertedFromCalendarValue() {
+		Calendar c1 = Calendar.getInstance();
+		Calendar c2 = Calendar.getInstance();
+		Calendar c3 = Calendar.getInstance();
+		c1.setTimeInMillis(T1);
+		c2.setTimeInMillis(T2);
+		c3.setTimeInMillis(T3);
+		
+		Query q = em.createQuery(JPQL_NAMED);
+		q.setParameter("d",  c1, TemporalType.DATE);
+		q.setParameter("t",  c2, TemporalType.TIME);
+		q.setParameter("ts", c3, TemporalType.TIMESTAMP);
+		
+		assertEquals(1, q.getResultList().size());
+	}
+	
+	public void testPositionalParameterConvertedFromCalendarValue() {
+		Calendar c1 = Calendar.getInstance();
+		Calendar c2 = Calendar.getInstance();
+		Calendar c3 = Calendar.getInstance();
+		c1.setTimeInMillis(T1);
+		c2.setTimeInMillis(T2);
+		c3.setTimeInMillis(T3);
+		
+		Query q = em.createQuery(JPQL_POSITIONAL);
+		q.setParameter(1,  c1, TemporalType.DATE);
+		q.setParameter(2,  c2, TemporalType.TIME);
+		q.setParameter(3,  c3, TemporalType.TIMESTAMP);
+		
+		assertEquals(1, q.getResultList().size());
+	}
+	public void testNamedParameterConvertedFromDateValue() {
+		Date d1 = new Date(T1);
+		Date d2 = new Date(T2);
+		Date d3 = new Date(T3);
+		
+		Query q = em.createQuery(JPQL_NAMED);
+		q.setParameter("d",  d1, TemporalType.DATE);
+		q.setParameter("t",  d2, TemporalType.TIME);
+		q.setParameter("ts", d3, TemporalType.TIMESTAMP);
+		
+		assertEquals(1, q.getResultList().size());
+	}
+	
+	public void testPositionalParameterConvertedFromDateValue() {
+		Date d1 = new Date(T1);
+		Date d2 = new Date(T2);
+		Date d3 = new Date(T3);
+		
+		Query q = em.createQuery(JPQL_POSITIONAL);
+		q.setParameter(1,  d1, TemporalType.DATE);
+		q.setParameter(2,  d2, TemporalType.TIME);
+		q.setParameter(3,  d3, TemporalType.TIMESTAMP);
+		
+		assertEquals(1, q.getResultList().size());
+	}
+	
+	
+	public void testNamedParameterWithMismatchedValue() {
+		Date d1 = new Date(T1);
+		Date d2 = new Date(T2);
+		Date d3 = new Date(T3);
+		
+		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();
+			fail("Expeceted " + ArgumentException.class.getName());
+		} catch (ArgumentException ex) {
+			// good
+			System.err.println(ex.getMessage());
+		}
+	}
+	
+	public void testPositionalParameterWithMismatchedValue() {
+		Date d1 = new Date(T1);
+		Date d2 = new Date(T2);
+		Date d3 = new Date(T3);
+		
+		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();
+			fail("Expeceted " + ArgumentException.class.getName());
+		} catch (ArgumentException ex) {
+			// good
+			System.err.println(ex.getMessage());
+		}
+	}
+	
+	void verifyParams(String jpql, Class error, Object...params) {
+		EntityManager em = emf.createEntityManager();
+		em.getTransaction().begin();
+		Query query = em.createNativeQuery(jpql);
+		for (int i=0; params != null && i<params.length; i=+2) {
+			try {
+				if (params[i] instanceof Number) {
+					query.setParameter(((Number)params[i]).intValue(), params[i+1]);
+				} else { 
+					query.setParameter(params[i].toString(), params[i+1]);
+				}
+				if (error != null)
+					fail("Expected " + error.getName());
+			} catch (Exception e) {
+				if (error.isAssignableFrom(e.getClass())) {
+					System.err.println(e.getMessage());
+				} else {
+					e.printStackTrace();
+					fail();
+				}
+			} 
+				
+		}
+		em.getTransaction().commit();
+	}
+}

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/TestNonPrimaryKeyQueryParameters.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/TestNonPrimaryKeyQueryParameters.java?rev=681977&r1=681976&r2=681977&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/TestNonPrimaryKeyQueryParameters.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/TestNonPrimaryKeyQueryParameters.java Sat Aug  2 06:58:56 2008
@@ -80,7 +80,6 @@
 		EntityManager em = emf.createEntityManager();
 
 		Query query = em.createQuery("SELECT d from Department d");
-		query.setParameter(1, DEPT_NAME);
 		Department dept = (Department) query.getSingleResult();
 
 		assertEquals(FULLTIME_EMPLOYEE_COUNT, dept.getFullTimeEmployees()

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Binder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Binder.java?rev=681977&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Binder.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Binder.java Sat Aug  2 06:58:56 2008
@@ -0,0 +1,50 @@
+/*
+ * 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.jdbc.query.domain;
+
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class Binder {
+	@Id
+	@GeneratedValue
+	private long id;
+	
+	private int p1;
+	private String p2;
+	private double p3;
+	
+	protected Binder() {
+		this(-1, "-1" , -1.0);
+	}
+	
+	public Binder(int i1, String i2, double i3) {
+		p1 = i1;
+		p2 = i2;
+		p3 = i3;
+	}
+	
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/TimeKeeper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/TimeKeeper.java?rev=681977&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/TimeKeeper.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/TimeKeeper.java Sat Aug  2 06:58:56 2008
@@ -0,0 +1,65 @@
+/*
+ * 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.jdbc.query.domain;
+
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class TimeKeeper {
+	@Id
+	@GeneratedValue
+	private long id;
+	
+	@Column(name="D")
+	private Date date;
+	@Column(name="T")
+	private Time time;
+	@Column(name="TS")
+	private Timestamp tstamp;
+	
+	public Date getDate() {
+		return date;
+	}
+	public void setDate(Date date) {
+		this.date = date;
+	}
+	public Time getTime() {
+		return time;
+	}
+	public void setTime(Time time) {
+		this.time = time;
+	}
+	public Timestamp getTstamp() {
+		return tstamp;
+	}
+	public void setTstamp(Timestamp tstamp) {
+		this.tstamp = tstamp;
+	}
+	public long getId() {
+		return id;
+	}
+
+}

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestDupNamedQuery.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestDupNamedQuery.java?rev=681977&r1=681976&r2=681977&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestDupNamedQuery.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestDupNamedQuery.java Sat Aug  2 06:58:56 2008
@@ -55,7 +55,7 @@
         String ValueTwo) {
         EntityManager em = emf.createEntityManager();
 
-        List list = em.createNamedQuery(findOneQName).setParameter(1, nameOne)
+        List list = em.createNamedQuery(findOneQName).setParameter("fname", nameOne)
             .getResultList();
         assertNotNull(list);
         assertEquals(list.size(), 1);

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=681977&r1=681976&r2=681977&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 Sat Aug  2 06:58:56 2008
@@ -20,7 +20,10 @@
 
 import java.io.Serializable;
 import java.lang.reflect.Method;
+import java.sql.Time;
+import java.sql.Timestamp;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
@@ -30,9 +33,12 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
+
 import javax.persistence.FlushModeType;
 import javax.persistence.Query;
 import javax.persistence.TemporalType;
+import javax.swing.text.Position;
 
 import org.apache.commons.collections.map.LinkedMap;
 import org.apache.openjpa.enhance.Reflection;
@@ -50,543 +56,681 @@
 
 /**
  * Implementation of {@link Query} interface.
- *
+ * 
  * @author Marc Prud'hommeaux
  * @author Abe White
  * @nojavadoc
  */
-public class QueryImpl
-    implements OpenJPAQuerySPI, Serializable {
+public class QueryImpl implements OpenJPAQuerySPI, Serializable {
+
+	private static final Object[] EMPTY_ARRAY = new Object[0];
 
-    private static final Object[] EMPTY_ARRAY = new Object[0];
+	private static final Localizer _loc = Localizer.forPackage(QueryImpl.class);
 
-    private static final Localizer _loc = Localizer.forPackage
-        (QueryImpl.class);
+	private final DelegatingQuery _query;
+	private transient EntityManagerImpl _em;
+	private transient FetchPlan _fetch;
+
+	private Map<String, Object> _named;
+	private Map<Integer, Object> _positional;
+
+	private static Object GAP_FILLER = new Object();
+
+	/**
+	 * Constructor; supply factory exception translator and delegate.
+	 * 
+	 * @param em
+	 *            The EntityManager which created this query
+	 * @param ret
+	 *            Exception translater for this query
+	 * @param query
+	 *            The underlying "kernel" query.
+	 */
+	public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret,
+			org.apache.openjpa.kernel.Query query) {
+		_em = em;
+		_query = new DelegatingQuery(query, ret);
+	}
 
-    private final DelegatingQuery _query;
-    private transient EntityManagerImpl _em;
-    private transient FetchPlan _fetch;
-
-    private Map _named;
-    private List _positional;
-
-    /**
-     * Constructor; supply factory exception translator and delegate.
-     * 
-     * @param em
-     *            The EntityManager which created this query
-     * @param ret
-     *            Exception translater for this query
-     * @param query
-     *            The underlying "kernel" query.
-     */
-    public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret,
-        org.apache.openjpa.kernel.Query query) {
-        _em = em;
-        _query = new DelegatingQuery(query, ret);
-    }
-    
-    /**
-     * Constructor; supply factory and delegate.
-     * @deprecated
-     */
-    public QueryImpl(EntityManagerImpl em, org.apache.openjpa.kernel.Query query) {
-        this(em, null, query);
-    }
+	/**
+	 * Constructor; supply factory and delegate.
+	 * 
+	 * @deprecated
+	 */
+	public QueryImpl(EntityManagerImpl em, org.apache.openjpa.kernel.Query query) {
+		this(em, null, query);
+	}
 
-    /**
+	/**
 	 * Delegate.
 	 */
-    public org.apache.openjpa.kernel.Query getDelegate() {
-        return _query.getDelegate();
-    }
-
-    public OpenJPAEntityManager getEntityManager() {
-        return _em;
-    }
-
-    public String getLanguage() {
-        return _query.getLanguage();
-    }
-
-    public QueryOperationType getOperation() {
-        return QueryOperationType.fromKernelConstant(_query.getOperation());
-    }
-
-    public FetchPlan getFetchPlan() {
-        _em.assertNotCloseInvoked();
-        _query.assertNotSerialized();
-        _query.lock();
-        try {
-            if (_fetch == null)
-                _fetch = ((EntityManagerFactoryImpl) _em.
-                    getEntityManagerFactory()).toFetchPlan(_query.getBroker(),
-                    _query.getFetchConfiguration());
-            return _fetch;
-        } finally {
-            _query.unlock();
-        }
-    }
-
-    public String getQueryString() {
-        return _query.getQueryString();
-    }
-
-    public boolean getIgnoreChanges() {
-        return _query.getIgnoreChanges();
-    }
-
-    public OpenJPAQuery setIgnoreChanges(boolean ignore) {
-        _em.assertNotCloseInvoked();
-        _query.setIgnoreChanges(ignore);
-        return this;
-    }
-
-    public OpenJPAQuery addFilterListener(FilterListener listener) {
-        _em.assertNotCloseInvoked();
-        _query.addFilterListener(listener);
-        return this;
-    }
-
-    public OpenJPAQuery removeFilterListener(FilterListener listener) {
-        _em.assertNotCloseInvoked();
-        _query.removeFilterListener(listener);
-        return this;
-    }
-
-    public OpenJPAQuery addAggregateListener(AggregateListener listener) {
-        _em.assertNotCloseInvoked();
-        _query.addAggregateListener(listener);
-        return this;
-    }
-
-    public OpenJPAQuery removeAggregateListener(AggregateListener listener) {
-        _em.assertNotCloseInvoked();
-        _query.removeAggregateListener(listener);
-        return this;
-    }
-
-    public Collection getCandidateCollection() {
-        return _query.getCandidateCollection();
-    }
-
-    public OpenJPAQuery setCandidateCollection(Collection coll) {
-        _em.assertNotCloseInvoked();
-        _query.setCandidateCollection(coll);
-        return this;
-    }
-
-    public Class getResultClass() {
-        Class res = _query.getResultType();
-        if (res != null)
-            return res;
-        return _query.getCandidateType();
-    }
-
-    public OpenJPAQuery setResultClass(Class cls) {
-        _em.assertNotCloseInvoked();
-        if (ImplHelper.isManagedType(_em.getConfiguration(), cls))
-            _query.setCandidateType(cls, true);
-        else
-            _query.setResultType(cls);
-        return this;
-    }
-
-    public boolean hasSubclasses() {
-        return _query.hasSubclasses();
-    }
-
-    public OpenJPAQuery setSubclasses(boolean subs) {
-        _em.assertNotCloseInvoked();
-        Class cls = _query.getCandidateType();
-        _query.setCandidateExtent(_query.getBroker().newExtent(cls, subs));
-        return this;
-    }
-
-    public int getFirstResult() {
-        return asInt(_query.getStartRange());
-    }
-
-    public OpenJPAQuery setFirstResult(int startPosition) {
-        _em.assertNotCloseInvoked();
-        long end;
-        if (_query.getEndRange() == Long.MAX_VALUE)
-            end = Long.MAX_VALUE;
-        else
-            end = startPosition +
-                (_query.getEndRange() - _query.getStartRange());
-        _query.setRange(startPosition, end);
-        return this;
-    }
-
-    public int getMaxResults() {
-        return asInt(_query.getEndRange() - _query.getStartRange());
-    }
-
-    public OpenJPAQuery setMaxResults(int max) {
-        _em.assertNotCloseInvoked();
-        long start = _query.getStartRange();
-        if (max == Integer.MAX_VALUE)
-            _query.setRange(start, Long.MAX_VALUE);
-        else
-            _query.setRange(start, start + max);
-        return this;
-    }
-
-    public OpenJPAQuery compile() {
-        _em.assertNotCloseInvoked();
-        _query.compile();
-        return this;
-    }
-
-    private Object execute() {
-        if (_query.getOperation() != QueryOperations.OP_SELECT)
-            throw new InvalidStateException(_loc.get("not-select-query",
-                _query.getQueryString()), null, null, false);
-
-        validateParameters();
-
-        // handle which types of parameters we are using, if any
-        if (_positional != null)
-            return _query.execute(_positional.toArray());
-        if (_named != null)
-            return _query.execute(_named);
-        return _query.execute();
-    }
-
-    /**
-     * Validate that the types of the parameters are correct.
-     */
-    private void validateParameters() {
-        if (_positional != null) {
-            LinkedMap types = _query.getParameterTypes();
-            for (int i = 0,
-                size = Math.min(_positional.size(), types.size());
-                i < size; i++)
-                validateParameter(String.valueOf(i),
-                    (Class) types.getValue(i), _positional.get(i));
-        } else if (_named != null) {
-            Map types = _query.getParameterTypes();
-            for (Iterator i = _named.entrySet().iterator(); i.hasNext();) {
-                Map.Entry entry = (Map.Entry) i.next();
-                String name = (String) entry.getKey();
-                validateParameter(name, (Class) types.get(name),
-                    entry.getValue());
-            }
-        }
-    }
-
-    private void validateParameter(String paramDesc, Class type, Object param) {
-        // null parameters are allowed, so are not validated
-        if (param == null || type == null)
-            return;
-
-        // check the parameter against the wrapped type
-        if (!Filters.wrap(type).isInstance(param))
-            throw new ArgumentException(_loc.get("bad-param-type",
-                paramDesc, param.getClass().getName(), type.getName()),
-                null, null, false);
-    }
-
-    public List getResultList() {
-        _em.assertNotCloseInvoked();
-        Object ob = execute();
-        if (ob instanceof List) {
-            List ret = (List) ob;
-            if (ret instanceof ResultList)
-                return new DelegatingResultList((ResultList) ret,
-                    PersistenceExceptions.getRollbackTranslator(_em));
-            else
-                return ret;
-        }
-
-        return Collections.singletonList(ob);
-    }
-
-    /**
-     * Execute a query that returns a single result.
-     */
-    public Object getSingleResult() {
-        _em.assertNotCloseInvoked();
-        // temporarily set query to unique so that a single result is validated
-        // and returned; unset again in case the user executes query again
-        // via getResultList
-        _query.setUnique(true);
-        try {
-            return execute();
-        } finally {
-            _query.setUnique(false);
-        }
-    }
-
-    public int executeUpdate() {
-        _em.assertNotCloseInvoked();
-        if (_query.getOperation() == QueryOperations.OP_DELETE) {
-            // handle which types of parameters we are using, if any
-            if (_positional != null)
-                return asInt(_query.deleteAll(_positional.toArray()));
-            if (_named != null)
-                return asInt(_query.deleteAll(_named));
-            return asInt(_query.deleteAll());
-        }
-        if (_query.getOperation() == QueryOperations.OP_UPDATE) {
-            // handle which types of parameters we are using, if any
-            if (_positional != null)
-                return asInt(_query.updateAll(_positional.toArray()));
-            if (_named != null)
-                return asInt(_query.updateAll(_named));
-            return asInt(_query.updateAll());
-        }
-        throw new InvalidStateException(_loc.get("not-update-delete-query",
-            _query.getQueryString()), null, null, false);
-    }
-
-    /**
-     * Cast the specified long down to an int, first checking for overflow.
-     */
-    private static int asInt(long l) {
-        if (l > Integer.MAX_VALUE)
-            return Integer.MAX_VALUE;
-        if (l < Integer.MIN_VALUE) // unlikely, but we might as well check
-            return Integer.MIN_VALUE;
-        return (int) l;
-    }
-
-    public FlushModeType getFlushMode() {
-        return EntityManagerImpl.fromFlushBeforeQueries(_query.
-            getFetchConfiguration().getFlushBeforeQueries());
-    }
-
-    public OpenJPAQuery setFlushMode(FlushModeType flushMode) {
-        _em.assertNotCloseInvoked();
-        _query.getFetchConfiguration().setFlushBeforeQueries
-            (EntityManagerImpl.toFlushBeforeQueries(flushMode));
-        return this;
-    }
-
-    public OpenJPAQuery setHint(String key, Object value) {
-        _em.assertNotCloseInvoked();
-        if (key == null || !key.startsWith("openjpa."))
-            return this;
-        String k = key.substring("openjpa.".length());
-
-        try {
-            if ("Subclasses".equals(k)) {
-                if (value instanceof String)
-                    value = Boolean.valueOf((String) value);
-                setSubclasses(((Boolean) value).booleanValue());
-            } else if ("FilterListener".equals(k))
-                addFilterListener(Filters.hintToFilterListener(value,
-                    _query.getBroker().getClassLoader()));
-            else if ("FilterListeners".equals(k)) {
-                FilterListener[] arr = Filters.hintToFilterListeners(value,
-                    _query.getBroker().getClassLoader());
-                for (int i = 0; i < arr.length; i++)
-                    addFilterListener(arr[i]);
-            } else if ("AggregateListener".equals(k))
-                addAggregateListener(Filters.hintToAggregateListener(value,
-                    _query.getBroker().getClassLoader()));
-            else if ("FilterListeners".equals(k)) {
-                AggregateListener[] arr = Filters.hintToAggregateListeners
-                    (value, _query.getBroker().getClassLoader());
-                for (int i = 0; i < arr.length; i++)
-                    addAggregateListener(arr[i]);
-            } else if (k.startsWith("FetchPlan.")) {
-                k = k.substring("FetchPlan.".length());
-                hintToSetter(getFetchPlan(), k, value);
-            } else if (k.startsWith("hint.")) {
-                if ("hint.OptimizeResultCount".equals(k)) {
-                    if (value instanceof String) {
-                        try {
-                            value = new Integer((String) value);
-                        } catch (NumberFormatException nfe) {
-                        }
-                    }
-                    if (!(value instanceof Number) 
-                        || ((Number) value).intValue() < 0)
-                        throw new ArgumentException(_loc.get
-                            ("bad-query-hint-value", key, value), null, null, 
-                            false);
-                }
-                _query.getFetchConfiguration().setHint(key, value);
-            }
-            else
-                throw new ArgumentException(_loc.get("bad-query-hint", key),
-                    null, null, false);
-            return this;
-        } catch (Exception e) {
-            throw PersistenceExceptions.toPersistenceException(e);
-        }
-    }
-
-    private void hintToSetter(FetchPlan fetchPlan, String k, Object value) {
-        if (fetchPlan == null || k == null)
-            return;
-
-        Method setter = Reflection.findSetter(fetchPlan.getClass(), k, true);
-        Class paramType = setter.getParameterTypes()[0];
-        if (Enum.class.isAssignableFrom(paramType) && value instanceof String)
-            value = Enum.valueOf(paramType, (String) value);
-        
-        Filters.hintToSetter(fetchPlan, k, value);
-    }
-
-    public OpenJPAQuery setParameter(int position, Calendar value,
-        TemporalType t) {
-        return setParameter(position, value);
-    }
-
-    public OpenJPAQuery setParameter(int position, Date value,
-        TemporalType type) {
-        return setParameter(position, value);
-    }
-
-    public OpenJPAQuery setParameter(int position, Object value) {
-        _query.assertOpen();
-        _em.assertNotCloseInvoked();
-        _query.lock();
-        try {
-        	if (isNative() && position < 1) {
-        		throw new IllegalArgumentException(_loc.get("bad-pos-params", 
-        		      position, _query.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 ArrayList();
-
-            // make sure it is at least the requested size
-            while (_positional.size() < position)
-                _positional.add(null);
-
-            // note that we add it to position - 1, since setPosition
-            // starts at 1, while List starts at 0
-            _positional.set(position - 1, value);
-            return this;
-        } finally {
-            _query.unlock();
-        }
-    }
-
-    public OpenJPAQuery setParameter(String name, Calendar value,
-        TemporalType t) {
-        return setParameter(name, value);
-    }
-
-    public OpenJPAQuery setParameter(String name, Date value,
-        TemporalType type) {
-        return setParameter(name, value);
-    }
-
-    public OpenJPAQuery setParameter(String name, Object value) {
-        _query.assertOpen();
-        _em.assertNotCloseInvoked();
-        _query.lock();
-        try {
-        	if (isNative()) {
-        		throw new IllegalArgumentException(_loc.get("no-named-params", 
-        		    name, _query.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);
-            return this;
-        } finally {
-            _query.unlock();
-        }
-    }
-    
-    public boolean isNative() {
-    	return QueryLanguages.LANG_SQL.equals(getLanguage());
-    }
-
-    public boolean hasPositionalParameters() {
-        return _positional != null;
-    }
-
-    public Object[] getPositionalParameters() {
-        _query.lock();
-        try {
-            return (_positional == null) ? EMPTY_ARRAY : _positional.toArray();
-        } finally {
-            _query.unlock();
-        }
-    }
-
-    public OpenJPAQuery setParameters(Object... params) {
-        _query.assertOpen();
-        _em.assertNotCloseInvoked();
-        _query.lock();
-        try {
-            _positional = null;
-            _named = null;
-            if (params != null)
-                for (int i = 0; i < params.length; i++)
-                    setParameter(i + 1, params[i]);
-            return this;
-        } finally {
-            _query.unlock();
-        }
-    }
-
-    public Map getNamedParameters() {
-        _query.lock();
-        try {
-            return (_named == null) ? Collections.EMPTY_MAP
-                : Collections.unmodifiableMap(_named);
-        } finally {
-            _query.unlock();
-        }
-    }
-
-    public OpenJPAQuery setParameters(Map params) {
-        _query.assertOpen();
-        _em.assertNotCloseInvoked();
-        _query.lock();
-        try {
-            _positional = null;
-            _named = null;
-            if (params != null)
-                for (Map.Entry e : (Set<Map.Entry>) params.entrySet())
-                    setParameter((String) e.getKey(), e.getValue());
-            return this;
-        } finally {
-            _query.unlock();
-        }
-    }
-
-    public OpenJPAQuery closeAll() {
-        _query.closeAll();
-        return this;
-    }
-
-    public String[] getDataStoreActions(Map params) {
-        return _query.getDataStoreActions(params);
-    }
-
-    public int hashCode() {
-        return _query.hashCode();
-    }
-
-    public boolean equals(Object other) {
-        if (other == this)
-            return true;
-        if (!(other instanceof QueryImpl))
-            return false;
-        return _query.equals(((QueryImpl) other)._query);
+	public org.apache.openjpa.kernel.Query getDelegate() {
+		return _query.getDelegate();
+	}
+
+	public OpenJPAEntityManager getEntityManager() {
+		return _em;
+	}
+
+	public String getLanguage() {
+		return _query.getLanguage();
+	}
+
+	public QueryOperationType getOperation() {
+		return QueryOperationType.fromKernelConstant(_query.getOperation());
+	}
+
+	public FetchPlan getFetchPlan() {
+		_em.assertNotCloseInvoked();
+		_query.assertNotSerialized();
+		_query.lock();
+		try {
+			if (_fetch == null)
+				_fetch = ((EntityManagerFactoryImpl) _em
+						.getEntityManagerFactory()).toFetchPlan(_query
+						.getBroker(), _query.getFetchConfiguration());
+			return _fetch;
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public String getQueryString() {
+		return _query.getQueryString();
+	}
+
+	public boolean getIgnoreChanges() {
+		return _query.getIgnoreChanges();
+	}
+
+	public OpenJPAQuery setIgnoreChanges(boolean ignore) {
+		_em.assertNotCloseInvoked();
+		_query.setIgnoreChanges(ignore);
+		return this;
+	}
+
+	public OpenJPAQuery addFilterListener(FilterListener listener) {
+		_em.assertNotCloseInvoked();
+		_query.addFilterListener(listener);
+		return this;
+	}
+
+	public OpenJPAQuery removeFilterListener(FilterListener listener) {
+		_em.assertNotCloseInvoked();
+		_query.removeFilterListener(listener);
+		return this;
+	}
+
+	public OpenJPAQuery addAggregateListener(AggregateListener listener) {
+		_em.assertNotCloseInvoked();
+		_query.addAggregateListener(listener);
+		return this;
+	}
+
+	public OpenJPAQuery removeAggregateListener(AggregateListener listener) {
+		_em.assertNotCloseInvoked();
+		_query.removeAggregateListener(listener);
+		return this;
+	}
+
+	public Collection getCandidateCollection() {
+		return _query.getCandidateCollection();
+	}
+
+	public OpenJPAQuery setCandidateCollection(Collection coll) {
+		_em.assertNotCloseInvoked();
+		_query.setCandidateCollection(coll);
+		return this;
+	}
+
+	public Class getResultClass() {
+		Class res = _query.getResultType();
+		if (res != null)
+			return res;
+		return _query.getCandidateType();
+	}
+
+	public OpenJPAQuery setResultClass(Class cls) {
+		_em.assertNotCloseInvoked();
+		if (ImplHelper.isManagedType(_em.getConfiguration(), cls))
+			_query.setCandidateType(cls, true);
+		else
+			_query.setResultType(cls);
+		return this;
+	}
+
+	public boolean hasSubclasses() {
+		return _query.hasSubclasses();
+	}
+
+	public OpenJPAQuery setSubclasses(boolean subs) {
+		_em.assertNotCloseInvoked();
+		Class cls = _query.getCandidateType();
+		_query.setCandidateExtent(_query.getBroker().newExtent(cls, subs));
+		return this;
+	}
+
+	public int getFirstResult() {
+		return asInt(_query.getStartRange());
+	}
+
+	public OpenJPAQuery setFirstResult(int startPosition) {
+		_em.assertNotCloseInvoked();
+		long end;
+		if (_query.getEndRange() == Long.MAX_VALUE)
+			end = Long.MAX_VALUE;
+		else
+			end = startPosition
+					+ (_query.getEndRange() - _query.getStartRange());
+		_query.setRange(startPosition, end);
+		return this;
+	}
+
+	public int getMaxResults() {
+		return asInt(_query.getEndRange() - _query.getStartRange());
+	}
+
+	public OpenJPAQuery setMaxResults(int max) {
+		_em.assertNotCloseInvoked();
+		long start = _query.getStartRange();
+		if (max == Integer.MAX_VALUE)
+			_query.setRange(start, Long.MAX_VALUE);
+		else
+			_query.setRange(start, start + max);
+		return this;
+	}
+
+	public OpenJPAQuery compile() {
+		_em.assertNotCloseInvoked();
+		_query.compile();
+		return this;
+	}
+
+	private Object execute() {
+		if (_query.getOperation() != QueryOperations.OP_SELECT)
+			throw new InvalidStateException(_loc.get("not-select-query", _query
+					.getQueryString()), null, null, false);
+
+		validateParameters();
+
+		// handle which types of parameters we are using, if any
+		if (_positional != null)
+			return _query.execute(_positional);
+		if (_named != null)
+			return _query.execute(_named);
+		return _query.execute();
+	}
+	
+	/**
+	 * Validate that the types of the parameters are correct.
+	 * The idea is to catch as many validation error as possible at the facade
+	 * layer itself.
+	 * 
+	 * The expected parameters are parsed from the query and in a LinkedMap 
+	 *	key   : name of the parameter as declared in query
+	 *  value : expected Class of allowed value
+	 *  
+	 * The bound parameters depends on positional or named parameter style
+	 * 
+	 * TreeMap<Integer, Object> for positional parameters:
+	 *   key   : 1-based Integer index
+	 *   value : bound value. GAP_FILLER if the position is not set. This
+	 *   simplifies validation at the kernel layer
+	 *   
+	 * Map<String, Object> for named parameters:
+	 *   key   : parameter name
+	 *   value : the bound value
+	 *   
+	 *  Validation accounts for 
+	 *    a) gaps in positional parameters
+	 *       SELECT p FROM PObject p WHERE p.a1=?1 AND p.a3=?3
+	 *    
+	 *    b) repeated parameters
+	 *       SELECT p FROM PObject p WHERE p.a1=?1 AND p.a2=?1 AND p.a3=?2
+	 *       
+	 *    c) parameter is bound but not declared
+	 *    
+	 *    d) parameter is declared but not bound
+	 *    
+	 *    e) parameter does not match the value type
+	 *    
+	 *    f) parameter is primitive type but bound to null value
+	 */
+	private void validateParameters() {
+		String query = getQueryString();
+		if (_positional != null) {
+			LinkedMap expected = _query.getParameterTypes();
+			Map<Integer, Object> actual = _positional;
+			for (Object o : expected.keySet()) {
+				String position = (String) o;
+				Class expectedParamType = (Class) expected.get(position);
+				try {
+					Integer.parseInt(position);
+				} catch (NumberFormatException ex) {
+					newValidationException("param-style-mismatch", query,
+							expected.asList(),
+							Arrays.toString(actual.keySet().toArray()));
+				}
+				Object actualValue = actual.get(Integer.parseInt(position));
+				boolean valueUnspecified = (actualValue == GAP_FILLER)
+						|| (actualValue == null && (actual.size() < expected
+								.size()));
+				if (valueUnspecified) 
+					newValidationException("param-missing", position, query,
+							Arrays.toString(actual.keySet().toArray()));
+				
+				if (expectedParamType.isPrimitive() && actualValue == null)
+					newValidationException("param-type-null", 
+							position, query, expectedParamType.getName());
+				if (actualValue == null)
+					continue;
+				if (!Filters.wrap(expectedParamType).isInstance(actualValue)) 
+					newValidationException("param-type-mismatch",
+							position, query, actualValue,
+							actualValue.getClass().getName(),
+							expectedParamType.getName());
+				
+			}
+			for (Integer position : actual.keySet()) {
+				Object actualValue = actual.get(position);
+				Class expectedParamType = (Class) expected.get("" + position);
+				boolean paramExpected = expected.containsKey("" + position);
+				if (actualValue == GAP_FILLER) {
+					if (paramExpected) {
+						newValidationException("param-missing", position, query,
+								Arrays.toString(actual.keySet().toArray()));
+					}
+				} else {
+					if (!paramExpected)
+						newValidationException("param-extra", position, query,
+								expected.asList());
+					if (expectedParamType.isPrimitive() && actualValue == null)
+						newValidationException("param-type-null", 
+								position, query, expectedParamType.getName());
+					if (!Filters.wrap(expectedParamType)
+							.isInstance(actualValue)) 
+						newValidationException("param-type-mismatch",
+								position, query, actualValue,
+								actualValue.getClass().getName(),
+								expectedParamType.getName());
+					
+				}
+			}
+
+		} else if (_named != null) {
+			LinkedMap expected = _query.getParameterTypes();
+			// key : name of the parameter used while binding
+			// value : user supplied parameter value. null may mean either
+			// user has supplied a value or not specified at all
+			Map<String, Object> actual = _named;
+			for (Object o : expected.keySet()) {
+				String expectedName = (String) o;
+				Class expectedParamType = (Class) expected.get(expectedName);
+				Object actualValue = actual.get(expectedName);
+				boolean valueUnspecified = !actual.containsKey(expectedName);
+				if (valueUnspecified) {
+					newValidationException("param-missing", expectedName, query,
+							Arrays.toString(actual.keySet().toArray()));
+				}
+				if (expectedParamType.isPrimitive() && actualValue == null)
+					newValidationException("param-type-null", 
+							expectedName, query, expectedParamType.getName());
+				if (actualValue == null)
+					continue;
+				if (!Filters.wrap(expectedParamType).isInstance(actualValue)) {
+					newValidationException("param-type-mismatch",
+							expectedName, query, actualValue,
+							actualValue.getClass().getName(),
+							expectedParamType.getName());
+				}
+			}
+			for (String actualName : actual.keySet()) {
+				Object actualValue = actual.get(actualName);
+				Class expectedParamType = (Class) expected.get(actualName);
+				boolean paramExpected = expected.containsKey(actualName);
+				if (!paramExpected) {
+					newValidationException("param-extra", actualName, query,
+							expected.asList());
+				}
+				if (expectedParamType.isPrimitive() && actualValue == null)
+					newValidationException("param-type-null", 
+							actualName, query, expectedParamType.getName());
+				if (!Filters.wrap(expectedParamType).isInstance(actualValue)) {
+					newValidationException("param-type-mismatch",
+							actualName, query, actualValue,
+							actualValue.getClass().getName(),
+							expectedParamType.getName());
+				}
+			}
+		}
+	}
+
+	void newValidationException(String msgKey, Object...args) {
+		throw new ArgumentException(_loc.get(msgKey, args), null, null, false);
+	}
+
+	public List getResultList() {
+		_em.assertNotCloseInvoked();
+		Object ob = execute();
+		if (ob instanceof List) {
+			List ret = (List) ob;
+			if (ret instanceof ResultList)
+				return new DelegatingResultList((ResultList) ret,
+						PersistenceExceptions.getRollbackTranslator(_em));
+			else
+				return ret;
+		}
+
+		return Collections.singletonList(ob);
+	}
+
+	/**
+	 * Execute a query that returns a single result.
+	 */
+	public Object getSingleResult() {
+		_em.assertNotCloseInvoked();
+		// temporarily set query to unique so that a single result is validated
+		// and returned; unset again in case the user executes query again
+		// via getResultList
+		_query.setUnique(true);
+		try {
+			return execute();
+		} finally {
+			_query.setUnique(false);
+		}
+	}
+
+	public int executeUpdate() {
+		_em.assertNotCloseInvoked();
+		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());
+		}
+		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());
+		}
+		throw new InvalidStateException(_loc.get("not-update-delete-query",
+				_query.getQueryString()), null, null, false);
+	}
+
+	/**
+	 * Cast the specified long down to an int, first checking for overflow.
+	 */
+	private static int asInt(long l) {
+		if (l > Integer.MAX_VALUE)
+			return Integer.MAX_VALUE;
+		if (l < Integer.MIN_VALUE) // unlikely, but we might as well check
+			return Integer.MIN_VALUE;
+		return (int) l;
+	}
+
+	public FlushModeType getFlushMode() {
+		return EntityManagerImpl.fromFlushBeforeQueries(_query
+				.getFetchConfiguration().getFlushBeforeQueries());
+	}
+
+	public OpenJPAQuery setFlushMode(FlushModeType flushMode) {
+		_em.assertNotCloseInvoked();
+		_query.getFetchConfiguration().setFlushBeforeQueries(
+				EntityManagerImpl.toFlushBeforeQueries(flushMode));
+		return this;
+	}
+
+	public OpenJPAQuery setHint(String key, Object value) {
+		_em.assertNotCloseInvoked();
+		if (key == null || !key.startsWith("openjpa."))
+			return this;
+		String k = key.substring("openjpa.".length());
+
+		try {
+			if ("Subclasses".equals(k)) {
+				if (value instanceof String)
+					value = Boolean.valueOf((String) value);
+				setSubclasses(((Boolean) value).booleanValue());
+			} else if ("FilterListener".equals(k))
+				addFilterListener(Filters.hintToFilterListener(value, _query
+						.getBroker().getClassLoader()));
+			else if ("FilterListeners".equals(k)) {
+				FilterListener[] arr = Filters.hintToFilterListeners(value,
+						_query.getBroker().getClassLoader());
+				for (int i = 0; i < arr.length; i++)
+					addFilterListener(arr[i]);
+			} else if ("AggregateListener".equals(k))
+				addAggregateListener(Filters.hintToAggregateListener(value,
+						_query.getBroker().getClassLoader()));
+			else if ("FilterListeners".equals(k)) {
+				AggregateListener[] arr = Filters.hintToAggregateListeners(
+						value, _query.getBroker().getClassLoader());
+				for (int i = 0; i < arr.length; i++)
+					addAggregateListener(arr[i]);
+			} else if (k.startsWith("FetchPlan.")) {
+				k = k.substring("FetchPlan.".length());
+				hintToSetter(getFetchPlan(), k, value);
+			} else if (k.startsWith("hint.")) {
+				if ("hint.OptimizeResultCount".equals(k)) {
+					if (value instanceof String) {
+						try {
+							value = new Integer((String) value);
+						} catch (NumberFormatException nfe) {
+						}
+					}
+					if (!(value instanceof Number)
+							|| ((Number) value).intValue() < 0)
+						throw new ArgumentException(_loc.get(
+								"bad-query-hint-value", key, value), null,
+								null, false);
+				}
+				_query.getFetchConfiguration().setHint(key, value);
+			} else
+				throw new ArgumentException(_loc.get("bad-query-hint", key),
+						null, null, false);
+			return this;
+		} catch (Exception e) {
+			throw PersistenceExceptions.toPersistenceException(e);
+		}
+	}
+
+	private void hintToSetter(FetchPlan fetchPlan, String k, Object value) {
+		if (fetchPlan == null || k == null)
+			return;
+
+		Method setter = Reflection.findSetter(fetchPlan.getClass(), k, true);
+		Class paramType = setter.getParameterTypes()[0];
+		if (Enum.class.isAssignableFrom(paramType) && value instanceof String)
+			value = Enum.valueOf(paramType, (String) value);
+
+		Filters.hintToSetter(fetchPlan, k, value);
+	}
+
+	public OpenJPAQuery setParameter(int position, Calendar value,
+			TemporalType t) {
+		return setParameter(position, convertTemporalType(value, t));
+	}
+
+	public OpenJPAQuery setParameter(int position, Date value, TemporalType type) {
+		return setParameter(position, convertTemporalType(value, type));
+	}
+
+	/**
+	 * Converts the given Date to a value corresponding to given temporal type.
+	 */
+
+	Object convertTemporalType(Date value, TemporalType type) {
+		switch (type) {
+		case DATE:
+			return value;
+		case TIME:
+			return new Time(value.getTime());
+		case TIMESTAMP:
+			return new Timestamp(value.getTime());
+		default:
+			return null;
+		}
+	}
+
+	Object convertTemporalType(Calendar value, TemporalType type) {
+		return convertTemporalType(value.getTime(), type);
+	}
+
+	public OpenJPAQuery setParameter(int position, Object value) {
+		_query.assertOpen();
+		_em.assertNotCloseInvoked();
+		_query.lock();
+		try {
+			if (isNative() && position < 1) {
+				throw new IllegalArgumentException(_loc.get("bad-pos-params",
+						position, _query.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>();
+
+			_positional.put(position, value);
+			for (int i = 1; i < position; i++)
+				if (!_positional.containsKey(i))
+					_positional.put(i, GAP_FILLER);
+
+			return this;
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public OpenJPAQuery setParameter(String name, Calendar value,
+			TemporalType type) {
+		return setParameter(name, convertTemporalType(value, type));
+	}
+
+	public OpenJPAQuery setParameter(String name, Date value, TemporalType type) {
+		return setParameter(name, convertTemporalType(value, type));
+	}
+
+	public OpenJPAQuery setParameter(String name, Object value) {
+		_query.assertOpen();
+		_em.assertNotCloseInvoked();
+		_query.lock();
+		try {
+			if (isNative()) {
+				throw new IllegalArgumentException(_loc.get("no-named-params",
+						name, _query.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);
+			return this;
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public boolean isNative() {
+		return QueryLanguages.LANG_SQL.equals(getLanguage());
+	}
+
+	public boolean hasPositionalParameters() {
+		return _positional != null;
+	}
+
+	/**
+	 * 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.
+	 */
+	public Object[] getPositionalParameters() {
+		_query.lock();
+		try {
+			return (_positional == null) ? EMPTY_ARRAY : _positional.values()
+					.toArray();
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public OpenJPAQuery setParameters(Object... params) {
+		_query.assertOpen();
+		_em.assertNotCloseInvoked();
+		_query.lock();
+		try {
+			_positional = null;
+			_named = null;
+			if (params != null)
+				for (int i = 0; i < params.length; i++)
+					setParameter(i + 1, params[i]);
+			return this;
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public Map getNamedParameters() {
+		_query.lock();
+		try {
+			return (_named == null) ? Collections.EMPTY_MAP : Collections
+					.unmodifiableMap(_named);
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public OpenJPAQuery setParameters(Map params) {
+		_query.assertOpen();
+		_em.assertNotCloseInvoked();
+		_query.lock();
+		try {
+			_positional = null;
+			_named = null;
+			if (params != null)
+				for (Map.Entry e : (Set<Map.Entry>) params.entrySet())
+					setParameter((String) e.getKey(), e.getValue());
+			return this;
+		} finally {
+			_query.unlock();
+		}
+	}
+
+	public OpenJPAQuery closeAll() {
+		_query.closeAll();
+		return this;
+	}
+
+	public String[] getDataStoreActions(Map params) {
+		return _query.getDataStoreActions(params);
+	}
+
+	public int hashCode() {
+		return _query.hashCode();
+	}
+
+	public boolean equals(Object other) {
+		if (other == this)
+			return true;
+		if (!(other instanceof QueryImpl))
+			return false;
+		return _query.equals(((QueryImpl) other)._query);
 	}
 }

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=681977&r1=681976&r2=681977&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 Sat Aug  2 06:58:56 2008
@@ -102,8 +102,10 @@
 	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 "{0}" is of type "{1}", but the \
-	declaration in the query is for type "{2}". 
+bad-param-type: The parameter "{1}" in query "{0}" is set to a value of type \
+	"{2}", but the parameter binds to a field of type "{3}". 
+missing-param-name: The parameter "{1}" in query "{0}" is not found in the \
+	available list of parameters "{2}".
 bad-em-prop: Invalid EntityManager property passed to createEntityManager. \
 	Key: "{0}", Value: "{1}".
 bad-em-props: Invalid EntityManager properties passed to createEntityManager. \
@@ -148,4 +150,14 @@
 EntityManagerFactory-displayorder: 50
 EntityManagerFactory-expert: true
 EntityManagerFactory-interface: org.apache.openjpa.persistence.EntityManagerFactoryImpl
-
+param-style-mismatch: Query "{0}" is declared with named parameters "{1}" but \
+	actual parameters "{2}" are bound by position.
+param-missing: Parameter "{0}" declared in "{1}" but is missing from the bound \
+	parameters "{2}".
+param-extra: Parameter "{0}" is bound to "{1}" but is missing from the \
+	declared parameters "{2}".
+param-type-mismatch: Parameter "{0}" declared in "{1}" is set to value of \
+	"{2}" of type "{3}", but this parameter is bound to a field of type "{4}".
+param-type-mismatch: Parameter "{0}" declared in "{1}" is set to null, \
+	but this parameter is bound to a field of primitive type "{2}".
+	
\ No newline at end of file