Author: ppoddar
Date: Sat Jan 31 19:37:01 2009
New Revision: 739589

URL: http://svn.apache.org/viewvc?rev=739589&view=rev
Log:
OPENJPA-703: Support PersistenceCapable as query parameter during 
reparameterization of Prepared Query.

Modified:
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Company.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
    
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java?rev=739589&r1=739588&r2=739589&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java
 Sat Jan 31 19:37:01 2009
@@ -24,11 +24,17 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.MappingRepository;
+import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.SelectExecutor;
+import org.apache.openjpa.kernel.Broker;
 import org.apache.openjpa.kernel.PreparedQuery;
 import org.apache.openjpa.kernel.Query;
 import org.apache.openjpa.lib.rop.ResultList;
+import org.apache.openjpa.util.ImplHelper;
+import org.apache.openjpa.util.InternalException;
 
 /**
  * Implements {...@link PreparedQuery} for SQL queries.
@@ -138,9 +144,9 @@
      * must be compatible with the user parameters extracted during 
      * {...@link #initialize(Object) initialization}. 
      * 
-     * @return key index starting from 1 and corresponding values.
+     * @return 0-based parameter index mapped to corresponding values.
      */
-    public Map<Integer, Object> reparametrize(Map user) {
+    public Map<Integer, Object> reparametrize(Map user, Broker broker) {
         Map<Integer, Object> result = new HashMap<Integer, Object>();
         for (int i = 0; i < _params.size(); i++) {
             result.put(i, _params.get(i));
@@ -151,13 +157,54 @@
             int[] indices = _userParamPositions.get(key);
             if (indices == null)
                 continue;
-            for (int j : indices)
-                result.put(j, user.get(key));
+            Object value = user.get(key);
+            if (ImplHelper.isManageable(value)) {
+                setPersistenceCapableParameter(result, value, indices, broker);
+            } else {
+                for (int j : indices)
+                    result.put(j, value);
+            }
         }
         return result;
     }
     
     /**
+     * Calculate primary key identity value(s) of the given managable instance
+     * and fill in the given map.
+     * 
+     * @param values a map of integer parameter index to parameter value
+     * @param pc a manageable instance
+     * @param indices the indices of the column values
+     * @param broker used to obtain the primary key values
+     */
+    private void setPersistenceCapableParameter(Map<Integer,Object> result, 
+        Object pc, int[] indices, Broker broker) {
+        JDBCStore store = (JDBCStore)broker.getStoreManager()
+            .getInnermostDelegate();
+        MappingRepository repos = store.getConfiguration()
+            .getMappingRepositoryInstance();
+        ClassMapping mapping = repos.getMapping(pc.getClass(), 
+            broker.getClassLoader(), true);
+        Column[] pks = mapping.getPrimaryKeyColumns();
+        Object cols = mapping.toDataStoreValue(pc, pks, store);
+        if (cols instanceof Object[]) {
+            Object[] array = (Object[])cols;
+            int n = array.length;
+            if (n > indices.length || indices.length%n != 0)
+                throw new InternalException();
+            int k = 0;
+            for (int j : indices) {
+                result.put(j, array[k%n]);
+                k++;
+            }
+        } else {
+            for (int j : indices) {
+                result.put(j, cols);
+            }
+        } 
+    }
+    
+    /**
      * Marks the positions of user parameters.
      * 
      * @param list odd elements are numbers representing the position of a 

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java?rev=739589&r1=739588&r2=739589&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
 Sat Jan 31 19:37:01 2009
@@ -93,6 +93,6 @@
         * @param user the map of parameter key and value set by the user on the
         * original query.
         */
-       public Map reparametrize(Map user);
+       public Map reparametrize(Map user, Broker broker);
        
 }

Modified: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Company.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Company.java?rev=739589&r1=739588&r2=739589&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Company.java
 (original)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Company.java
 Sat Jan 31 19:37:01 2009
@@ -25,10 +25,14 @@
 
 @Entity
 @NamedQueries({
-       @NamedQuery(name="Company.PreparedQueryWithNoParameter", query="select 
x from Company x"),
-       @NamedQuery(name="Company.PreparedQueryWithNamedParameter", 
query="select x from Company x where x.name=:name and x.startYear=:startYear"),
-       @NamedQuery(name="Company.PreparedQueryWithPositionalParameter", 
query="select x from Company x where x.name=?1 and x.startYear=?2"),
-       @NamedQuery(name="Company.PreparedQueryWithLiteral", query="select x 
from Company x where x.name='X' and x.startYear=1960")
+       @NamedQuery(name="Company.PreparedQueryWithNoParameter", 
+           query="select x from Company x"),
+       @NamedQuery(name="Company.PreparedQueryWithNamedParameter", 
+           query="select x from Company x where x.name=:name and 
x.startYear=:startYear"),
+       @NamedQuery(name="Company.PreparedQueryWithPositionalParameter", 
+           query="select x from Company x where x.name=?1 and x.startYear=?2"),
+       @NamedQuery(name="Company.PreparedQueryWithLiteral", 
+           query="select x from Company x where x.name='IBM' and 
x.startYear=1900")
 })
 public class Company {
        @Id

Modified: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java?rev=739589&r1=739588&r2=739589&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
 (original)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
 Sat Jan 31 19:37:01 2009
@@ -20,8 +20,11 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
+import javax.persistence.EntityManager;
+
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.kernel.PreparedQuery;
 import org.apache.openjpa.kernel.QueryHints;
@@ -33,6 +36,7 @@
 import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
 import org.apache.openjpa.persistence.OpenJPAPersistence;
 import org.apache.openjpa.persistence.OpenJPAQuery;
+import org.apache.openjpa.persistence.test.SQLListenerTestCase;
 import org.apache.openjpa.persistence.test.SingleEMFTestCase;
 
 /**
@@ -42,33 +46,65 @@
  * @author Pinaki Poddar
  * 
  */
-public class TestPreparedQueryCache extends SingleEMFTestCase {
+public class TestPreparedQueryCache extends SQLListenerTestCase {
        // Fail if performance degrades with cache compared to without cache
-       public static final boolean FAIL_ON_PERF_DEGRADE = 
-               Boolean.getBoolean("FailOnPerformanceRegression");
+    public static final boolean FAIL_ON_PERF_DEGRADE = 
+        Boolean.getBoolean("FailOnPerformanceRegression");
        
        // # observations to compute timing statistics
        public static final int SAMPLE_SIZE = 100;
        
        public static final boolean USE_CACHE                  = true;
-       public static final boolean BIND_DIFFERENT_PARM_VALUES = true;
        public static final boolean IS_NAMED_QUERY             = true;
        
-       public static final String[] COMPANY_NAMES = { "acme.org" };
+    public static final String[] COMPANY_NAMES = {"IBM", "BEA", "acme.org" };
+    public static final int[] START_YEARS = {1900, 2000, 2010 };
        public static final String[] DEPARTMENT_NAMES = { "Marketing", "Sales",
                        "Engineering" };
        public static final String[] EMPLOYEE_NAMES = { "Tom", "Dick", "Harray" 
};
+       public static final String[] CITY_NAMES = {"Tulsa", "Durban", "Harlem"};
        
        public static final String EXCLUDED_QUERY_1 = "select count(p) from 
Company p";
        public static final String EXCLUDED_QUERY_2 = "select count(p) from 
Department p";
        public static final String INCLUDED_QUERY   = "select p from Address p";
+       private Company IBM;
        
        public void setUp() throws Exception {
                super.setUp(Company.class, Department.class, Employee.class,
                                Address.class, 
-                               "openjpa.Log", "SQL=WARN",
                                "openjpa.QuerySQLCache", 
                                "true(excludes='select count(p) from Company 
p;select count(p) from Department p')");
+               createTestData();
+       }
+       
+       void createTestData() {
+           EntityManager em = emf.createEntityManager();
+           em.getTransaction().begin();
+           for (int i = 0; i < COMPANY_NAMES.length; i++) {
+               Company company = new Company();
+               if (i == 0) 
+                   IBM = company;
+               company.setName(COMPANY_NAMES[i]);
+               company.setStartYear(START_YEARS[i]);
+               em.persist(company);
+               for (int j = 0; j < DEPARTMENT_NAMES.length; j++) {
+                   Department dept = new Department();
+                   dept.setName(DEPARTMENT_NAMES[j]);
+                   company.addDepartment(dept);
+                   em.persist(dept);
+                   for (int k = 0; k < EMPLOYEE_NAMES.length; k++) {
+                       Employee emp = new Employee();
+                       emp.setName(EMPLOYEE_NAMES[k]);
+                       Address addr = new Address();
+                       addr.setCity(CITY_NAMES[k]);
+                    em.persist(emp);
+                       em.persist(addr);
+                       emp.setAddress(addr);
+                    dept.addEmployees(emp);
+                   }
+               }
+           }
+           em.getTransaction().commit();
        }
 
        public void tearDown() throws Exception {
@@ -323,56 +359,60 @@
        public void testQueryWithNoParameter() {
                String jpql = "select p from Company p";
                Object[] params = null;
-               compare(!IS_NAMED_QUERY, jpql, BIND_DIFFERENT_PARM_VALUES, 
params);
+               compare(!IS_NAMED_QUERY, jpql, COMPANY_NAMES.length, params);
        }
 
        public void testQueryWithLiteral() {
-               String jpql = "select p from Company p where p.name = 
'PObject'";
+               String jpql = "select p from Company p where p.name = " + 
literal(COMPANY_NAMES[0]);
                Object[] params = null;
-               compare(!IS_NAMED_QUERY, jpql, BIND_DIFFERENT_PARM_VALUES, 
params);
+               compare(!IS_NAMED_QUERY, jpql, 1, params);
        }
 
        public void testQueryWithParameter() {
                String jpql = "select p from Company p where p.name = :param";
-               Object[] params = {"param", "x"};
-               compare(!IS_NAMED_QUERY, jpql, BIND_DIFFERENT_PARM_VALUES, 
params);
+               Object[] params = {"param", COMPANY_NAMES[0]};
+               compare(!IS_NAMED_QUERY, jpql, 1, params);
        }
 
        public void testQueryWithJoinsAndParameters() {
-               String jpql = "select e from Employee e " + "where e.name = 
:emp "
-                                       + "and e.department.name = :dept "
-                                       + "and e.department.company.name LIKE 
'IBM' " 
-                                       + "and e.department.company.name = 
:company " 
-                                       + "and e.address.zip = :zip";
-               Object[] params = { "emp", "John", 
-                                                       "dept", "Engineering",
-                                                       "company", "acme.org",
-                                                       "zip", 12345};
-               compare(!IS_NAMED_QUERY, jpql, BIND_DIFFERENT_PARM_VALUES, 
params);
+               String jpql = "select e from Employee e " + "where e.name = 
:emp"
+                                       + " and e.department.name = :dept"
+                                       + " and e.department.company.name LIKE  
" + literal(COMPANY_NAMES[0]) 
+                                       + " and e.address.city = :city";
+               Object[] params = { "emp", EMPLOYEE_NAMES[0], 
+                                                       "dept", 
DEPARTMENT_NAMES[0],
+                                                       "city", CITY_NAMES[0]};
+               compare(!IS_NAMED_QUERY, jpql, 1, params);
        }
 
        public void testNamedQueryWithNoParameter() {
                String namedQuery = "Company.PreparedQueryWithNoParameter";
                Object[] params = null;
-               compare(IS_NAMED_QUERY, namedQuery, BIND_DIFFERENT_PARM_VALUES, 
params);
+               compare(IS_NAMED_QUERY, namedQuery, COMPANY_NAMES.length, 
params);
        }
 
        public void testNamedQueryWithLiteral() {
                String namedQuery = "Company.PreparedQueryWithLiteral";
                Object[] params = null;
-               compare(IS_NAMED_QUERY, namedQuery, BIND_DIFFERENT_PARM_VALUES, 
params);
+               compare(IS_NAMED_QUERY, namedQuery, 1, params);
        }
 
        public void testNamedQueryWithPositionalParameter() {
                String namedQuery = 
"Company.PreparedQueryWithPositionalParameter";
-               Object[] params = {1, "x", 2, 1960};
-               compare(IS_NAMED_QUERY, namedQuery, BIND_DIFFERENT_PARM_VALUES, 
params);
+               Object[] params = {1, COMPANY_NAMES[0], 2, START_YEARS[0]};
+               compare(IS_NAMED_QUERY, namedQuery, 1, params);
        }
        
        public void testNamedQueryWithNamedParameter() {
                String namedQuery = "Company.PreparedQueryWithNamedParameter";
-               Object[] params = {"name", "x", "startYear", 1960};
-               compare(IS_NAMED_QUERY, namedQuery, BIND_DIFFERENT_PARM_VALUES, 
params);
+               Object[] params = {"name", COMPANY_NAMES[0], "startYear", 
START_YEARS[0]};
+               compare(IS_NAMED_QUERY, namedQuery, 1, params);
+       }
+       
+       public void testPersistenceCapableParameter() {
+           String jpql = "select e from Employee e where 
e.department.company=:company";
+           Object[] params = {"company", IBM};
+           compare(!IS_NAMED_QUERY, jpql, 
EMPLOYEE_NAMES.length*DEPARTMENT_NAMES.length, params);
        }
        
        /**
@@ -380,36 +420,36 @@
         * Prepared Query Cache.
         * 
         */
-       void compare(boolean isNamed, String jpql, boolean append, Object... 
params) {
+       void compare(boolean isNamed, String jpql, int expectedCount, Object... 
params) {
                String realJPQL = isNamed ? getJPQL(jpql) : jpql;
                // run the query once for warming up 
-               run(jpql, params, !USE_CACHE, 1, isNamed, append);
+               run(jpql, params, !USE_CACHE, 1, isNamed, expectedCount);
                
                // run N times without cache
-               long without = run(jpql, params, !USE_CACHE, SAMPLE_SIZE, 
isNamed, append);
+               long without = run(jpql, params, !USE_CACHE, SAMPLE_SIZE, 
isNamed, expectedCount);
                assertNotCached(realJPQL);
                
                // run N times with cache
-               long with = run(jpql, params, USE_CACHE, SAMPLE_SIZE, isNamed, 
append);
+               long with = run(jpql, params, USE_CACHE, SAMPLE_SIZE, isNamed, 
expectedCount);
                assertCached(realJPQL);
                
                long delta = (without == 0) ? 0 : (without - with) * 100 / 
without;
                
                String sql = getSQL(realJPQL);
-               System.err.println("Execution time in nanos for " + SAMPLE_SIZE
+               log("Execution time in nanos for " + SAMPLE_SIZE
                                + " query execution with and without SQL 
cache:" + with + " "
                                + without + " (" + delta + "%)");
-               System.err.println("JPQL: " + realJPQL);
-               System.err.println("SQL : " + sql);
+               log("JPQL: " + realJPQL);
+               log("SQL : " + sql);
                if (delta < 0) {
                        if (FAIL_ON_PERF_DEGRADE)
                                assertFalse("change in execution time = " + 
delta + "%", 
                                                delta < 0);
                        else 
-                               System.err.println("*** WARN: Perforamce 
regression with cache." + 
+                               log("*** WARN: Perforamce regression with 
cache." + 
                                        " Execution time degrades by " + delta 
+ "%");
                } else {
-                   System.err.println("change in execution time = +" + delta + 
"%");
+                   log("change in execution time = +" + delta + "%");
                }
        }
 
@@ -421,12 +461,14 @@
         * returns median time taken for single execution.
         */
        long run(String jpql, Object[] params, boolean useCache, int N, 
-                       boolean isNamedQuery, boolean 
appendIndexValuetoParameters) {
-               OpenJPAEntityManager em = emf.createEntityManager();
-               ((OpenJPAEntityManagerSPI)em).setQuerySQLCache(useCache);
-               assertEquals(useCache, 
((OpenJPAEntityManagerSPI)em).getQuerySQLCache());
+                       boolean isNamedQuery, int expectedCount) {
+           trace("Executing " + N + " times " + (useCache ? " with " : 
"without") + " cache");
                List<Long> stats = new ArrayList<Long>();
+               sql.clear();
                for (int i = 0; i < N; i++) {
+               OpenJPAEntityManager em = emf.createEntityManager();
+               ((OpenJPAEntityManagerSPI)em).setQuerySQLCache(useCache);
+               assertEquals(useCache, 
((OpenJPAEntityManagerSPI)em).getQuerySQLCache());
                        long start = System.nanoTime();
                        OpenJPAQuery q = isNamedQuery 
                                ? em.createNamedQuery(jpql) : 
em.createQuery(jpql);
@@ -438,15 +480,26 @@
                                else if (key instanceof String)
                                        q.setParameter(key.toString(), val); 
                                else
-                                       throw new RuntimeException("key " + key 
+ " is neither Number nor String");
+                                       fail("key " + key + " is neither Number 
nor String");
                        }
-                       q.getResultList();
+                       List list = q.getResultList();
+                       walk(list);
+                       int actual = list.size();
                        q.closeAll();
+                       assertEquals(expectedCount, actual);
                        long end = System.nanoTime();
                        stats.add(end - start);
+               em.close();
                }
-               em.close();
-               Collections.sort(stats);
+        if (useCache) {
+            String cacheKey = isNamedQuery ? getJPQL(jpql) : jpql;
+            long total = 
getCache().getStatistics().getExecutionCount(cacheKey);
+            long hits = getCache().getStatistics().getHitCount(cacheKey);
+            assertEquals(N, total);
+            assertEquals(N-1, hits);
+        }
+        assertEquals(N, sql.size());
+        Collections.sort(stats);
                return stats.get(N/2);
        }       
        
@@ -468,28 +521,23 @@
                                  .getQueryMetaData(null, namedQuery, null, 
true)
                                  .getQueryString();
        }
-
-
-
-       public static void main(String[] args) throws Exception {
-               TestPreparedQueryCache _this = new TestPreparedQueryCache();
-               _this.setUp();
-               String jpql = "select e from Employee e where e.name = :emp and 
"
-                               + "e.department.name = :dept and "
-                               + "e.department.company.name = :company and 
e.address.zip = :zip";
-               Object[] params = { "emp", "John", "dept", "Engineering", 
"company",
-                               "acme.org", "zip", 12345 };
-               System.err.println("Executing  100 times [" + jpql + "]");
-               System.err.println("Press return to continue...");
-//             System.in.read();
-               long start = System.nanoTime();
-               _this.run(jpql, params, 
-                               USE_CACHE, 
-                               SAMPLE_SIZE, 
-                               !IS_NAMED_QUERY, 
-                               BIND_DIFFERENT_PARM_VALUES);
-               long end = System.nanoTime();
-               System.err.println("Time taken " + (end-start) + "ns");
+       
+       String literal(String s) {
+           return "'"+s+"'";
+       }
+       
+    void log(String s) {
+        System.err.println(s);
+    }
+    
+    void trace(String s) {
+        if (Boolean.getBoolean("trace"))
+            System.err.println(s);
+    }
+       
+       void walk(List list) {
+           Iterator i = list.iterator();
+           while (i.hasNext())
+               i.next();
        }
-
 }

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=739589&r1=739588&r2=739589&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 Jan 31 19:37:01 2009
@@ -265,7 +265,7 @@
                    QueryStatistics stats = cache.getStatistics();
                    if (alreadyCached && LANG_PREPARED_SQL.equals(lang)) {
                        PreparedQuery pq = _em.getPreparedQuery(_id);
-                       params = pq.reparametrize(params);
+                       params = pq.reparametrize(params, _em.getBroker());
                        stats.recordExecution(pq.getOriginalQuery(), 
alreadyCached);
                    } else {
                 stats.recordExecution(_query.getQueryString(), alreadyCached);


Reply via email to