diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java index 8d521d53c..1b3a99b32 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java @@ -156,30 +156,30 @@ public final class SQLBuffer _cols.add(paramIndex, null); } } - if (buf._userIndex != null) { - if (_userIndex == null) - _userIndex = new ArrayList(); + + // adding user parameters from another buffer to this buffer + // this buffer's user parameter index gets modified + if (buf._userIndex == null && this._userIndex == null) { + // do nothing + } else if (buf._userIndex != null && this._userIndex == null) { + // copy the other buffers data + this._userIndex = new ArrayList(buf._userIndex); + } else if (buf._userIndex == null && this._userIndex != null) { + // nothing to add from the other buffer + } else { // both has data. + // modify this buffer's user parameter index + int otherSize = buf._userIndex.size()/2; + for (int i = 0; i < _userIndex.size(); i+=2) { + int newIndex = ((Integer)_userIndex.get(i)).intValue() + otherSize; + _userIndex.set(i, newIndex); + } + // append the other buffer's user parameters to this one for (int i = 0; i < buf._userIndex.size(); i+=2) { - int newIndex = ((Integer)buf._userIndex.get(i)).intValue() - + paramIndex; - Object userParam = buf._userIndex.get(i+1); - _userIndex.add(newIndex); - _userIndex.add(userParam); - } - } else { - if (_userIndex != null) { - List userIndex = new ArrayList(); - for (int i = 0; i < _userIndex.size(); i+=2) { - int oldIndex = ((Integer)_userIndex.get(i)).intValue(); - Object userParam = _userIndex.get(i+1); - if (oldIndex >= paramIndex) - userIndex.add(oldIndex + paramIndex); - else - userIndex.add(oldIndex); - userIndex.add(userParam); - } - _userIndex = userIndex; - } + Object otherIndex = buf._userIndex.get(i); + Object otherParam = buf._userIndex.get(i+1); + _userIndex.add(otherIndex); + _userIndex.add(otherParam); + } } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/OrderJPA.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/OrderJPA.java new file mode 100644 index 000000000..87d77aae6 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/OrderJPA.java @@ -0,0 +1,64 @@ +/* + * 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.sqlcache; + +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * A simple entity for a complex test. + * This entity is used to test complex parameterization and reparametrization of Prepared Queries. + * + * @author Pinaki Poddar + * + */ +@Entity +public class OrderJPA { + @Id + long OrderId; + int CustomerId; + int DistrictId; + int WarehouseId; + + + public long getOrderId() { + return OrderId; + } + public void setOrderId(long orderId) { + OrderId = orderId; + } + public int getCustomerId() { + return CustomerId; + } + public void setCustomerId(int customerId) { + CustomerId = customerId; + } + public int getDistrictId() { + return DistrictId; + } + public void setDistrictId(int districtId) { + DistrictId = districtId; + } + public int getWarehouseId() { + return WarehouseId; + } + public void setWarehouseId(int warehouseId) { + WarehouseId = warehouseId; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java index cddca2f91..59b88a1f6 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java @@ -187,7 +187,24 @@ public class TestPreparedQueryCache extends TestCase { em.persist(b1); em.persist(b2); em.persist(c1); em.persist(c2); - em.getTransaction().commit(); + id = (int)System.currentTimeMillis(); + OrderJPA o1 = new OrderJPA(); + o1.setOrderId(id++); + o1.setCustomerId(339); + o1.setDistrictId(3); + o1.setWarehouseId(23); + + OrderJPA o2 = new OrderJPA(); + o2.setOrderId(id++); + o2.setCustomerId(2967); + o2.setDistrictId(5); + o2.setWarehouseId(22); + + em.persist(o1); + em.persist(o2); + + + em.getTransaction().commit(); } public void tearDown() throws Exception { @@ -835,6 +852,129 @@ public class TestPreparedQueryCache extends TestCase { assertFalse(q2.getResultList().isEmpty()); } + public void testRepeatedParameterInSubqueryInDifferentOrder() { + OpenJPAEntityManager em = emf.createEntityManager(); + String jpql = "select o from OrderJPA o " + + "where o.OrderId in (select max(o1.OrderId) from OrderJPA o1 " + + "where ((o1.CustomerId = :customerId) " + + "and (o1.DistrictId = :districtId) " + + "and (o1.WarehouseId = :warehouseId))) " + + "and (o.CustomerId = :customerId) " + + "and (o.WarehouseId = :warehouseId) " + + "and (o.DistrictId = :districtId)"; + + em.getTransaction().begin(); + TypedQuery q1 = em.createQuery(jpql, OrderJPA.class); + q1.setParameter("customerId", 339) + .setParameter("districtId", 3) + .setParameter("warehouseId", 23); + + assertEquals(JPQLParser.LANG_JPQL, OpenJPAPersistence.cast(q1).getLanguage()); + assertFalse(q1.getResultList().isEmpty()); + + + TypedQuery q2 = em.createQuery(jpql, OrderJPA.class); + assertEquals(QueryLanguages.LANG_PREPARED_SQL, OpenJPAPersistence.cast(q2).getLanguage()); + q2.setParameter("customerId", 2967) + .setParameter("districtId", 5) + .setParameter("warehouseId", 22); + + assertFalse(q2.getResultList().isEmpty()); + em.getTransaction().rollback(); + } + + public void testRepeatedParameterInSubqueryInSameOrder() { + OpenJPAEntityManager em = emf.createEntityManager(); + String jpql = "select o from OrderJPA o " + + "where o.OrderId in (select max(o1.OrderId) from OrderJPA o1 " + + "where ((o1.CustomerId = :customerId) " + + "and (o1.DistrictId = :districtId) " + + "and (o1.WarehouseId = :warehouseId))) " + + "and (o.CustomerId = :customerId) " + + "and (o.DistrictId = :districtId) " + + "and (o.WarehouseId = :warehouseId)"; + + em.getTransaction().begin(); + TypedQuery q1 = em.createQuery(jpql, OrderJPA.class); + q1.setParameter("customerId", 339) + .setParameter("districtId", 3) + .setParameter("warehouseId", 23); + + assertEquals(JPQLParser.LANG_JPQL, OpenJPAPersistence.cast(q1).getLanguage()); + assertFalse(q1.getResultList().isEmpty()); + + + TypedQuery q2 = em.createQuery(jpql, OrderJPA.class); + assertEquals(QueryLanguages.LANG_PREPARED_SQL, OpenJPAPersistence.cast(q2).getLanguage()); + q2.setParameter("customerId", 2967) + .setParameter("districtId", 5) + .setParameter("warehouseId", 22); + + assertFalse(q2.getResultList().isEmpty()); + em.getTransaction().rollback(); + } + + public void testPartiallyRepeatedParameterInSubquery() { + OpenJPAEntityManager em = emf.createEntityManager(); + String jpql = "select o from OrderJPA o " + + "where o.OrderId in (select max(o1.OrderId) from OrderJPA o1 " + + "where ((o1.CustomerId = :customerId) " + + "and (o1.WarehouseId = :warehouseId))) " + + "and (o.CustomerId = :customerId) " + + "and (o.DistrictId = :districtId) " + + "and (o.WarehouseId = :warehouseId)"; + + em.getTransaction().begin(); + TypedQuery q1 = em.createQuery(jpql, OrderJPA.class); + q1.setParameter("customerId", 339) + .setParameter("districtId", 3) + .setParameter("warehouseId", 23); + + assertEquals(JPQLParser.LANG_JPQL, OpenJPAPersistence.cast(q1).getLanguage()); + assertFalse(q1.getResultList().isEmpty()); + + + TypedQuery q2 = em.createQuery(jpql, OrderJPA.class); + assertEquals(QueryLanguages.LANG_PREPARED_SQL, OpenJPAPersistence.cast(q2).getLanguage()); + q2.setParameter("customerId", 2967) + .setParameter("districtId", 5) + .setParameter("warehouseId", 22); + + assertFalse(q2.getResultList().isEmpty()); + em.getTransaction().rollback(); + } + + public void testPartiallyRepeatedParameterInMainquery() { + OpenJPAEntityManager em = emf.createEntityManager(); + String jpql = "select o from OrderJPA o " + + "where o.OrderId in (select max(o1.OrderId) from OrderJPA o1 " + + "where ((o1.CustomerId = :customerId) " + + "and (o1.DistrictId = :districtId) " + + "and (o1.WarehouseId = :warehouseId))) " + + "and (o.CustomerId = :customerId) " + + "and (o.WarehouseId = :warehouseId)"; + + em.getTransaction().begin(); + TypedQuery q1 = em.createQuery(jpql, OrderJPA.class); + q1.setParameter("customerId", 339) + .setParameter("districtId", 3) + .setParameter("warehouseId", 23); + + assertEquals(JPQLParser.LANG_JPQL, OpenJPAPersistence.cast(q1).getLanguage()); + assertFalse(q1.getResultList().isEmpty()); + + + TypedQuery q2 = em.createQuery(jpql, OrderJPA.class); + assertEquals(QueryLanguages.LANG_PREPARED_SQL, OpenJPAPersistence.cast(q2).getLanguage()); + q2.setParameter("customerId", 2967) + .setParameter("districtId", 5) + .setParameter("warehouseId", 22); + + assertFalse(q2.getResultList().isEmpty()); + em.getTransaction().rollback(); + } + + PreparedQueryCache getPreparedQueryCache() { return emf.getConfiguration().getQuerySQLCacheInstance(); diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml index d5c76d4e9..6231182dd 100644 --- a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml @@ -207,6 +207,7 @@ org.apache.openjpa.persistence.jdbc.sqlcache.Merchandise org.apache.openjpa.persistence.jdbc.sqlcache.Person org.apache.openjpa.persistence.jdbc.sqlcache.Singer + org.apache.openjpa.persistence.jdbc.sqlcache.OrderJPA