Author: awhite Date: Tue Mar 27 12:24:54 2007 New Revision: 523046 URL: http://svn.apache.org/viewvc?view=rev&rev=523046 Log: OPENJPA-181 : Fix class cast exception by passing along the StoreQuery context whenever we pass around an Executor, so that the StoreQuery and Executor are always matched.
Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java (with props) incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java (with props) Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java?view=diff&rev=523046&r1=523045&r2=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java (original) +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java Tue Mar 27 12:24:54 2007 @@ -108,11 +108,11 @@ implements Executor { public Number executeDelete(StoreQuery q, Object[] params) { - return q.getContext().deleteInMemory(this, params); + return q.getContext().deleteInMemory(q, this, params); } public Number executeUpdate(StoreQuery q, Object[] params) { - return q.getContext().updateInMemory(this, params); + return q.getContext().updateInMemory(q, this, params); } public String[] getDataStoreActions(StoreQuery q, Object[] params, Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java?view=diff&rev=523046&r1=523045&r2=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java (original) +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java Tue Mar 27 12:24:54 2007 @@ -403,17 +403,19 @@ } } - public Number deleteInMemory(StoreQuery.Executor ex, Object[] params) { + public Number deleteInMemory(StoreQuery q, StoreQuery.Executor ex, + Object[] params) { try { - return _query.deleteInMemory(ex, params); + return _query.deleteInMemory(q, ex, params); } catch (RuntimeException re) { throw translate(re); } } - public Number updateInMemory(StoreQuery.Executor ex, Object[] params) { + public Number updateInMemory(StoreQuery q, StoreQuery.Executor ex, + Object[] params) { try { - return _query.updateInMemory(ex, params); + return _query.updateInMemory(q, ex, params); } catch (RuntimeException re) { throw translate(re); } Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java?view=diff&rev=523046&r1=523045&r2=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java (original) +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java Tue Mar 27 12:24:54 2007 @@ -679,7 +679,7 @@ Number num = ((ExpressionStoreQuery) q).executeDelete(this, _meta, _metas, _subs, _facts, _exps, params); if (num == null) - return q.getContext().deleteInMemory(this, params); + return q.getContext().deleteInMemory(q, this, params); return num; } @@ -687,7 +687,7 @@ Number num = ((ExpressionStoreQuery) q).executeUpdate(this, _meta, _metas, _subs, _facts, _exps, params); if (num == null) - return q.getContext().updateInMemory(this, params); + return q.getContext().updateInMemory(q, this, params); return num; } Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java?view=diff&rev=523046&r1=523045&r2=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java (original) +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java Tue Mar 27 12:24:54 2007 @@ -252,13 +252,15 @@ * Helper method to delete the objects found by executing a query on * the given executor. */ - public Number deleteInMemory(StoreQuery.Executor ex, Object[] params); + public Number deleteInMemory(StoreQuery q, StoreQuery.Executor ex, + Object[] params); /** * Helper method to update the objects found by executing a query on * the given executor. */ - public Number updateInMemory(StoreQuery.Executor ex, Object[] params); + public Number updateInMemory(StoreQuery q, StoreQuery.Executor ex, + Object[] params); /** * Helper method to instantiate the class with the given name, taking Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java?view=diff&rev=523046&r1=523045&r2=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java (original) +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java Tue Mar 27 12:24:54 2007 @@ -558,7 +558,7 @@ try { assertOpen(); StoreQuery.Executor ex = compileForExecutor(); - getResultPacker(ex); + getResultPacker(_storeQuery, ex); ex.validate(_storeQuery); } finally { unlock(); @@ -782,17 +782,17 @@ StoreQuery.Executor ex = (isInMemory(operation)) ? compileForInMemory(comp) : compileForDataStore(comp); - assertParameters(ex, params); + assertParameters(_storeQuery, ex, params); if (_log.isTraceEnabled()) logExecution(operation, ex.getParameterTypes(_storeQuery), params); if (operation == OP_SELECT) - return execute(ex, params); + return execute(_storeQuery, ex, params); if (operation == OP_DELETE) - return delete(ex, params); + return delete(_storeQuery, ex, params); if (operation == OP_UPDATE) - return update(ex, params); + return update(_storeQuery, ex, params); throw new UnsupportedException(); } catch (OpenJPAException ke) { throw ke; @@ -826,16 +826,16 @@ Object[] arr = (params.isEmpty()) ? StoreQuery.EMPTY_OBJECTS : toParameterArray(ex.getParameterTypes(_storeQuery), params); - assertParameters(ex, arr); + assertParameters(_storeQuery, ex, arr); if (_log.isTraceEnabled()) logExecution(operation, params); if (operation == OP_SELECT) - return execute(ex, arr); + return execute(_storeQuery, ex, arr); if (operation == OP_DELETE) - return delete(ex, arr); + return delete(_storeQuery, ex, arr); if (operation == OP_UPDATE) - return update(ex, arr); + return update(_storeQuery, ex, arr); throw new UnsupportedException(); } catch (OpenJPAException ke) { throw ke; @@ -964,21 +964,22 @@ * values. All other execute methods delegate to this one or to * [EMAIL PROTECTED] #execute(StoreQuery.Executor,Map)} after validation and locking. */ - private Object execute(StoreQuery.Executor ex, Object[] params) + private Object execute(StoreQuery q, StoreQuery.Executor ex, + Object[] params) throws Exception { // if this is an impossible result range, return null / empty list StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx); if (!_rangeSet) - ex.getRange(_storeQuery, params, range); + ex.getRange(q, params, range); if (range.start >= range.end) - return emptyResult(ex); + return emptyResult(q, ex); // execute; if we have a result class or we have only one result // and so need to remove it from its array, wrap in a packing rop range.lrs = isLRS(range.start, range.end); - ResultObjectProvider rop = ex.executeQuery(_storeQuery, params, range); + ResultObjectProvider rop = ex.executeQuery(q, params, range); try { - return toResult(ex, rop, range); + return toResult(q, ex, rop, range); } catch (Exception e) { if (rop != null) try { rop.close(); } catch (Exception e2) {} @@ -993,16 +994,16 @@ * The return value will be a Number indicating the number of * instances deleted. */ - private Number delete(StoreQuery.Executor ex, Object[] params) + private Number delete(StoreQuery q, StoreQuery.Executor ex, Object[] params) throws Exception { - assertBulkModify(ex, params); - return ex.executeDelete(_storeQuery, params); + assertBulkModify(q, ex, params); + return ex.executeDelete(q, params); } - public Number deleteInMemory(StoreQuery.Executor executor, + public Number deleteInMemory(StoreQuery q, StoreQuery.Executor executor, Object[] params) { try { - Object o = execute(executor, params); + Object o = execute(q, executor, params); if (!(o instanceof Collection)) o = Collections.singleton(o); @@ -1024,16 +1025,16 @@ * The return value will be a Number indicating the number of * instances updated. */ - private Number update(StoreQuery.Executor ex, Object[] params) + private Number update(StoreQuery q, StoreQuery.Executor ex, Object[] params) throws Exception { - assertBulkModify(ex, params); - return ex.executeUpdate(_storeQuery, params); + assertBulkModify(q, ex, params); + return ex.executeUpdate(q, params); } - public Number updateInMemory(StoreQuery.Executor executor, + public Number updateInMemory(StoreQuery q, StoreQuery.Executor executor, Object[] params) { try { - Object o = execute(executor, params); + Object o = execute(q, executor, params); if (!(o instanceof Collection)) o = Collections.singleton(o); @@ -1188,13 +1189,13 @@ /** * Return the query result for the given result object provider. */ - protected Object toResult(StoreQuery.Executor ex, ResultObjectProvider rop, - StoreQuery.Range range) + protected Object toResult(StoreQuery q, StoreQuery.Executor ex, + ResultObjectProvider rop, StoreQuery.Range range) throws Exception { // pack projections if necessary - String[] aliases = ex.getProjectionAliases(_storeQuery); - if (!ex.isPacking(_storeQuery)) { - ResultPacker packer = getResultPacker(ex); + String[] aliases = ex.getProjectionAliases(q); + if (!ex.isPacking(q)) { + ResultPacker packer = getResultPacker(q, ex); if (packer != null || aliases.length == 1) rop = new PackingResultObjectProvider(rop, packer, aliases.length); @@ -1202,15 +1203,14 @@ // if single result, extract it if (_unique == Boolean.TRUE || (aliases.length > 0 - && !ex.hasGrouping(_storeQuery) && ex.isAggregate(_storeQuery))) + && !ex.hasGrouping(q) && ex.isAggregate(q))) return singleResult(rop, range); // now that we've executed the query, we can call isAggregate and // hasGrouping efficiently boolean detach = (_broker.getAutoDetach() & AutoDetach.DETACH_NONTXREAD) > 0 && !_broker.isActive(); - boolean lrs = range.lrs && !ex.isAggregate(_storeQuery) - && !ex.hasGrouping(_storeQuery); + boolean lrs = range.lrs && !ex.isAggregate(q) && !ex.hasGrouping(q); ResultList res = (!detach && lrs) ? _fc.newResultList(rop) : new EagerResultList(rop); @@ -1228,23 +1228,23 @@ /** * Return a result packer for this projection, or null. */ - private ResultPacker getResultPacker(StoreQuery.Executor ex) { + private ResultPacker getResultPacker(StoreQuery q, StoreQuery.Executor ex) { if (_packer != null) return _packer; Class resultClass = (_resultClass != null) ? _resultClass - : ex.getResultClass(_storeQuery); + : ex.getResultClass(q); if (resultClass == null) return null; - String[] aliases = ex.getProjectionAliases(_storeQuery); + String[] aliases = ex.getProjectionAliases(q); if (aliases.length == 0) { // result class but no result; means candidate is being set // into some result class _packer = new ResultPacker(_class, getAlias(), resultClass); } else if (resultClass != null) { // projection - Class[] types = ex.getProjectionTypes(_storeQuery); + Class[] types = ex.getProjectionTypes(q); _packer = new ResultPacker(types, aliases, resultClass); } return _packer; @@ -1253,9 +1253,9 @@ /** * Create an empty result for this query. */ - private Object emptyResult(StoreQuery.Executor ex) { + private Object emptyResult(StoreQuery q, StoreQuery.Executor ex) { if (_unique == Boolean.TRUE || (_unique == null - && !ex.hasGrouping(_storeQuery) && ex.isAggregate(_storeQuery))) + && !ex.hasGrouping(q) && ex.isAggregate(q))) return null; return Collections.EMPTY_LIST; } @@ -1387,7 +1387,7 @@ StoreQuery.Executor ex = compileForExecutor(); Object[] arr = toParameterArray(ex.getParameterTypes(_storeQuery), params); - assertParameters(ex, arr); + assertParameters(_storeQuery, ex, arr); StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx); if (!_rangeSet) ex.getRange(_storeQuery, arr, range); @@ -1636,14 +1636,15 @@ * Check that we are in a state to be able to perform a bulk operation; * also flush the current modfications if any elements are currently dirty. */ - private void assertBulkModify(StoreQuery.Executor ex, Object[] params) { + private void assertBulkModify(StoreQuery q, StoreQuery.Executor ex, + Object[] params) { _broker.assertActiveTransaction(); if (_startIdx != 0 || _endIdx != Long.MAX_VALUE) throw new UserException(_loc.get("no-modify-range")); if (_resultClass != null) throw new UserException(_loc.get("no-modify-resultclass")); StoreQuery.Range range = new StoreQuery.Range(); - ex.getRange(_storeQuery, params, range); + ex.getRange(q, params, range); if (range.start != 0 || range.end != Long.MAX_VALUE) throw new UserException(_loc.get("no-modify-range")); } @@ -1651,11 +1652,12 @@ /** * Checks that the passed parameters match the declarations. */ - protected void assertParameters(StoreQuery.Executor ex, Object[] params) { - if (!_storeQuery.requiresParameterDeclarations()) + protected void assertParameters(StoreQuery q, StoreQuery.Executor ex, + Object[] params) { + if (!q.requiresParameterDeclarations()) return; - LinkedMap paramTypes = ex.getParameterTypes(_storeQuery); + LinkedMap paramTypes = ex.getParameterTypes(q); int typeCount = paramTypes.size(); if (typeCount > params.length) throw new UserException(_loc.get("unbound-params", Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java?view=auto&rev=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java (added) +++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java Tue Mar 27 12:24:54 2007 @@ -0,0 +1,42 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed 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.datacache; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + [EMAIL PROTECTED] +public class CascadeChild { + + @Id + @GeneratedValue + private long id; + + private String name; + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java ------------------------------------------------------------------------------ svn:executable = * Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java?view=auto&rev=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java (added) +++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java Tue Mar 27 12:24:54 2007 @@ -0,0 +1,55 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed 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.datacache; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToOne; + [EMAIL PROTECTED] +public class CascadeParent { + + @Id + @GeneratedValue + private long id; + + private String name; + + @OneToOne(cascade=CascadeType.ALL) + private CascadeChild child; + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public CascadeChild getChild() { + return child; + } + + public void setChild(CascadeChild child) { + this.child = child; + } +} Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java ------------------------------------------------------------------------------ svn:executable = * Modified: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java?view=diff&rev=523046&r1=523045&r2=523046 ============================================================================== --- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java (original) +++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java Tue Mar 27 12:24:54 2007 @@ -2,6 +2,7 @@ import java.util.List; import java.util.Map; +import javax.persistence.EntityManager; import org.apache.openjpa.persistence.OpenJPAEntityManager; import org.apache.openjpa.persistence.OpenJPAPersistence; @@ -14,7 +15,7 @@ private Object oid; public TestBulkJPQLAndDataCache() { - super(AllFieldTypes.class); + super(AllFieldTypes.class, CascadeParent.class, CascadeChild.class); } @Override @@ -43,6 +44,24 @@ em.close(); } + public void tearDown() + throws Exception { + if (emf == null) + return; + try { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + em.createQuery("DELETE FROM AllFieldTypes").executeUpdate(); + em.createQuery("DELETE FROM CascadeParent").executeUpdate(); + em.createQuery("DELETE FROM CascadeChild").executeUpdate(); + em.getTransaction().commit(); + em.close(); + } catch (Exception e) { + } + + super.tearDown(); + } + public void testBulkDelete() { OpenJPAEntityManager em = OpenJPAPersistence.cast(emf.createEntityManager()); @@ -86,6 +105,40 @@ assertFalse(OpenJPAPersistence.cast(emf).getStoreCache() .contains(AllFieldTypes.class, oid)); + em.close(); + } + + public void testBulkDeleteOfCascadingEntity() { + CascadeParent parent = new CascadeParent(); + parent.setName("parent"); + CascadeChild child = new CascadeChild(); + child.setName("child"); + parent.setChild(child); + + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(parent); + em.getTransaction().commit(); + em.close(); + + em = emf.createEntityManager(); + assertEquals(1, em.createQuery("SELECT o FROM CascadeParent o"). + getResultList().size()); + assertEquals(1, em.createQuery("SELECT o FROM CascadeChild o"). + getResultList().size()); + em.close(); + + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.createQuery("DELETE FROM CascadeParent o").executeUpdate(); + em.getTransaction().commit(); + em.close(); + + em = emf.createEntityManager(); + assertEquals(0, em.createQuery("SELECT o FROM CascadeParent o"). + getResultList().size()); + assertEquals(0, em.createQuery("SELECT o FROM CascadeChild o"). + getResultList().size()); em.close(); } }