From cb271bfa1d343a9637e4120679f941d25457ffbc Mon Sep 17 00:00:00 2001 From: Jeremy Bauer Date: Tue, 17 Mar 2009 04:40:23 +0000 Subject: [PATCH] OPENJPA-878 Committing code, tests, and documentation updates for Donald Woods. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@755115 13f79535-47bb-0310-9956-ffa450edef68 --- .../persistence/jdbc/JDBCFetchPlan.java | 1 + .../persistence/jdbc/JDBCFetchPlanImpl.java | 5 + .../apache/openjpa/conf/TestQueryHints.java | 7 +- .../conf/TestOpenJPAConfiguration.java | 2 + .../persistence/query/TestQueryTimeout.java | 601 ++++++++++++++++++ .../query/common/apps/QTimeout.java | 86 +++ .../common/apps/META-INF/persistence.xml | 1 + 7 files changed, 700 insertions(+), 3 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/common/apps/QTimeout.java diff --git a/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.java b/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.java index d8bc48c2a..68378139e 100644 --- a/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.java +++ b/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.java @@ -145,6 +145,7 @@ public interface JDBCFetchPlan public JDBCFetchPlan setMaxFetchDepth(int depth); public JDBCFetchPlan setReadLockMode(LockModeType mode); public JDBCFetchPlan setWriteLockMode(LockModeType mode); + public JDBCFetchPlan setQueryTimeout(int timeout); /** * @deprecated use the {@link FetchMode} enum instead. diff --git a/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlanImpl.java b/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlanImpl.java index 1b6e9ec38..8db9d51de 100644 --- a/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlanImpl.java +++ b/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlanImpl.java @@ -287,4 +287,9 @@ public class JDBCFetchPlanImpl public JDBCFetchPlan setWriteLockMode(LockModeType mode) { return (JDBCFetchPlan) super.setWriteLockMode(mode); } + + @Override + public JDBCFetchPlan setQueryTimeout(int timeout) { + return (JDBCFetchPlan) super.setQueryTimeout(timeout); + } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java index 70ed281e0..0101f3e31 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java @@ -137,9 +137,10 @@ public class TestQueryHints extends SingleEMFTestCase { } public void testJPAHintSetsFetchPlan() { - String jpaKey = "javax.persistence.query.timeout"; - query.setHint(jpaKey, 5671); - assertEquals(5671, query.getFetchPlan().getQueryTimeout()); + query.setHint("javax.persistence.lock.timeout", 5671); + query.setHint("javax.persistence.query.timeout", 7500); + assertEquals(5671, query.getFetchPlan().getLockTimeout()); + assertEquals(7500, query.getFetchPlan().getQueryTimeout()); } public void testParts() { diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/conf/TestOpenJPAConfiguration.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/conf/TestOpenJPAConfiguration.java index b574e7c16..eeb693c05 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/conf/TestOpenJPAConfiguration.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/conf/TestOpenJPAConfiguration.java @@ -59,6 +59,7 @@ public class TestOpenJPAConfiguration map.put("openjpa.ConnectionFactory2", cfactory2); map.put("openjpa.Optimistic", Boolean.FALSE); map.put("openjpa.LockTimeout", new Integer(503)); + map.put("javax.persistence.query.timeout", new Integer(1500)); // use new conf so no unexpected restrictions on type of connection // factory @@ -68,6 +69,7 @@ public class TestOpenJPAConfiguration assertEquals(cfactory2, conf.getConnectionFactory2()); assertEquals(false, conf.getOptimistic()); assertEquals(503, conf.getLockTimeout()); + assertEquals(1500, conf.getQueryTimeout()); OpenJPAConfiguration conf2 = new OpenJPAConfigurationImpl(true, false); conf2.fromProperties(map); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java new file mode 100644 index 000000000..6fdf00b83 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java @@ -0,0 +1,601 @@ +/* + * 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.query; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; +import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.DerbyDictionary; +import org.apache.openjpa.kernel.Broker; +import org.apache.openjpa.lib.log.Log; +import org.apache.openjpa.persistence.JPAFacadeHelper; +import org.apache.openjpa.persistence.PersistenceException; +import org.apache.openjpa.persistence.QueryTimeoutException; +import org.apache.openjpa.persistence.query.common.apps.QTimeout; +import org.apache.openjpa.persistence.test.AllowFailure; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +/** + * Tests the new query timeout hint support in the JPA 2.0 spec. + * + * @version $Rev$ $Date$ + */ +public class TestQueryTimeout extends SQLListenerTestCase { + + private boolean skipTests = false; + // does the DB platform allow retry instead of forcing transaction rollback + private boolean supportsQueryTimeoutException = false; + + @Override + public void setUp() { + super.setUp(DROP_TABLES, QTimeout.class); + getLog().trace("setUp()"); + String[] _strings = new String[] { "a", "b", "c" }; + QTimeout qt = null; + EntityManager em = null; + + // determine if we should run our tests on this DB platform and what + // exception type to catch + DBDictionary dict = ((JDBCConfiguration) emf.getConfiguration()) + .getDBDictionaryInstance(); + if ((dict.supportsQueryTimeout) && (dict instanceof DerbyDictionary)) { + // set whether we expect to see QueryTimeoutException or + // PersistenceException + supportsQueryTimeoutException = false; + } else { + // FIXME drwoods - OPENJPA-964 - haven't determined what the other + // DBs support + // setQueryTimeout is not working with DB2 v9.5.3a on Windows... + getLog().info("TestQueryTimeout tests are being skipped, due to " + + "DB not supporting Query Timeouts."); + skipTests = true; + return; + } + + try { + em = emf.createEntityManager(); + assertNotNull(em); + getLog().trace("setUp() - creating Qtimeout entities"); + em.getTransaction().begin(); + for (int i = 0; i < _strings.length; i++) { + qt = new QTimeout(i, _strings[i]); + em.persist(qt); + } + em.getTransaction().commit(); + } catch (Exception e) { + fail("Unexpected setup exception occurred - " + e); + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + + // execute some native SQL with no timeouts + if (dict instanceof DerbyDictionary) { + getLog().trace("setUp() - creating DELAY function only for Derby." + + " Other DBs require manual setup."); + // remove existing function if it exists and ignore any errors + exec(true, 0, "DROP FUNCTION DELAY"); + exec(false, 0, "CREATE FUNCTION DELAY(SECONDS INTEGER, " + + "VALUE INTEGER) RETURNS INTEGER PARAMETER STYLE JAVA NO SQL " + + "LANGUAGE JAVA EXTERNAL NAME 'org.apache.openjpa.persistence." + + "query.TestQueryTimeout.delay'"); + } + getLog().trace("setUp() - creating BEFORE UPDATE/INSERT TRIGGERs for " + + "all DBs"); + exec(false, 0, "CREATE TRIGGER t1 NO CASCADE BEFORE UPDATE ON " + + "qtimeout FOR EACH ROW MODE DB2SQL values DELAY(2,-1)"); + exec(false, 0, "CREATE TRIGGER t2 NO CASCADE BEFORE INSERT ON " + + "qtimeout FOR EACH ROW MODE DB2SQL values DELAY(2,-2)"); + // Don't include a DELETE trigger, as it slows down the DROP_TABLES + // cleanup between tests + // exec(0, "CREATE TRIGGER t3 NO CASCADE BEFORE DELETE ON qtimeout " + + // "FOR EACH ROW MODE DB2SQL values DELAY(2,-3)"); + } + + /* + * Query timeout scenarios to test for: + * 1) By default, there is no timeout + * 2) Setting timeout to 0 is same as no timeout (JDBC defined) + * 2.1) using the QueryHint annotation + * 2.2) calling setHint() + * 3) Setting timeout to msecs < DELAY value causes new + * javax.persistence.QueryTimeoutException when set by: + * 3.1) using the QueryHint annotation + * 3.2) calling setHint() + * Operations to validate through cross coverage of items #1-#3: + * a) getResultList() + * b) getSingleResult() + * c) executeUpdate() + * Other behaviors to test for: + * 4) Setting timeout to < 0 should be treated as no timeout supplied + * Exception generation to test for: + * If the DB query timeout does not cause a transaction rollback, then a + * QueryTimeoutException should be thrown. + * Applicable to: unknown + * Else if the DB query timeout causes a transaction rollback, then a + * PersistenceException should be thrown instead of a QTE. + * Applicable to: Derby + */ + + /** + * Scenario being tested: 1a) By default, there is no timeout for queries. + * Expected Results: The DELAY function is being called and the query takes + * 6000+ msecs to complete. + */ + @AllowFailure(value=true, message="FIXME - The runtime >= 6K assertion " + + "in this test fails intermittently and needs to be corrected.") + public void testQueryTimeout1a() { + if (skipTests) { + return; + } + getLog().trace("testQueryTimeout1a() - No Query timeout"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Query q = em.createNamedQuery("NoHintList"); + // verify no default javax.persistence.query.timeout is supplied + Map hints = q.getHints(); + assertFalse(hints.containsKey("javax.persistence.query.timeout")); + try { + long startTime = System.currentTimeMillis(); + @SuppressWarnings("unchecked") + List results = q.getResultList(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace("testQueryTimeout1a() - NoHintList runTime" + + " msecs=" + runTime); + assertTrue("Should have taken 6000+ msecs", runTime >= 6000); + assertEquals("Verify we found the expected number of results.", + 2, results.size()); + } catch (Exception e) { + fail("Unexpected testQueryTimeout1a() exception = " + e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Scenario being tested: 1c) By default, there is no timeout for updates. + * Expected Results: The DELAY function is being called and the query takes + * 2000+ msecs to complete. + */ + public void testQueryTimeout1c() { + if (skipTests) { + return; + } + getLog().trace("testQueryTimeout1c() - No Update timeout"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + try { + long startTime = System.currentTimeMillis(); + QTimeout qt = em.find(QTimeout.class, new Integer(1)); + em.getTransaction().begin(); + qt.setStringField("updated"); + em.flush(); + em.getTransaction().commit(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace("testQueryTimeout1c() - EM find/update runTime" + + " msecs=" + runTime); + assertTrue("Should have taken 2000+ msecs", runTime >= 2000); + em.clear(); + qt = em.find(QTimeout.class, new Integer(1)); + assertEquals("Verify the entity was updated.", + qt.getStringField(), "updated"); + } catch (Exception e) { + fail("Unexpected testQueryTimeout1c() exception = " + e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Scenario being tested: 2.1.a) Explicit annotated QueryHint of timeout=0 + * is treated the same as the default no timeout for queries. + * Expected Results: The DELAY function is being called and the query + * takes 6000+ msecs to complete. + */ + @AllowFailure(value=true, message="FIXME - The runtime >= 6K assertion " + + "in this test fails intermittently and needs to be corrected.") + public void testQueryTimeout2a() { + if (skipTests) { + return; + } + getLog().trace("testQueryTimeout2a() - QueryHint=0"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Query q = em.createNamedQuery("Hint0msec"); + // verify javax.persistence.query.timeout is supplied + Map hints = q.getHints(); + assertTrue(hints.containsKey("javax.persistence.query.timeout")); + Integer timeout = new Integer( + (String) hints.get("javax.persistence.query.timeout")); + getLog().trace("testQueryTimeout2a() - Retrieved hint " + + "javax.persistence.query.timeout=" + timeout); + assertEquals(timeout, new Integer(0)); + + try { + long startTime = System.currentTimeMillis(); + @SuppressWarnings("unchecked") + List results = q.getResultList(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace("testQueryTimeout2a() - Hint0msec runTime msecs=" + + runTime); + assertTrue("Should have taken 6000+ msecs", runTime >= 6000); + assertEquals("Verify we found the expected number of results.", + 2, results.size()); + } catch (Exception e) { + fail("Unexpected testQueryTimeout2a() exception = " + e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Scenario being tested: 2.1.b) Explicit setHint of timeout=0 is treated + * the same as the default no timeout for queries. + * Expected Results: The DELAY function is being called and the query + * takes 2000+ msecs to complete. + */ + public void testQueryTimeout2b() { + if (skipTests) { + return; + } + Integer setTime = new Integer(0); + getLog().trace("testQueryTimeout2b() - setHint(" + setTime + ")"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Query q = em.createNamedQuery("NoHintSingle"); + + // verify no default javax.persistence.query.timeout is supplied + Map hints = q.getHints(); + assertFalse(hints.containsKey("javax.persistence.query.timeout")); + + // update the timeout value to 0 and verify it was set + getLog().trace("testQueryTimeout2b() - Setting hint " + + "javax.persistence.query.timeout=" + setTime); + q.setHint("javax.persistence.query.timeout", setTime); + hints = q.getHints(); + assertTrue(hints.containsKey("javax.persistence.query.timeout")); + Integer timeout = (Integer) hints.get( + "javax.persistence.query.timeout"); + getLog().trace("testQueryTimeout2b() - Retrieved hint " + + "javax.persistence.query.timeout=" + timeout); + assertEquals(timeout, setTime); + + try { + long startTime = System.currentTimeMillis(); + Object result = q.getSingleResult(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace("testQueryTimeout2b() - NoHintSingle runTime " + + "msecs=" + runTime); + assertTrue("Should have taken 2000+ msecs", runTime >= 2000); + assertNotNull("Verify we received a result.", result); + } catch (Exception e) { + fail("Unexpected testQueryTimeout2b() exception = " + e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Scenario being tested: 3.1.a) Explicit annotated QueryHint of + * timeout=1000 msecs will cause the query to timeout. + * Expected Results: QueryTimeoutException or PersistenceException + */ + public void testQueryTimeout3a() { + if (skipTests) { + return; + } + Integer setTime = new Integer(1000); + getLog().trace("testQueryTimeout3a() - QueryHint(" + setTime + ")"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Query q = em.createNamedQuery("Hint1000msec"); + + // verify javax.persistence.query.timeout hint via annotation set + Map hints = q.getHints(); + assertTrue(hints.containsKey("javax.persistence.query.timeout")); + Integer timeout = new Integer((String) hints.get( + "javax.persistence.query.timeout")); + getLog().trace( + "testQueryTimeout3a() - Found javax.persistence.query.timeout=" + + timeout); + assertTrue("Expected to find a javax.persistence.query.timeout=" + + setTime, (timeout.intValue() == setTime.intValue())); + + try { + long startTime = System.currentTimeMillis(); + @SuppressWarnings( { "unchecked", "unused" }) + List results = q.getResultList(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace( + "testQueryTimeout3a() - Hint1000msec runTime msecs=" + + runTime); + //assertEquals("Should never get valid results due to the " + + // "timeout.", 2, results.size()); + fail("QueryTimeout annotation failed to cause an Exception " + + "in testQueryTimeout3a(" + + setTime + " msecs), runTime msecs=" + runTime); + } catch (Exception e) { + // expected + checkException("testQueryTimeout3a()", e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Scenario being tested: 3.2.b) Explicit setHint of timeout to 1000 msecs + * will cause the query to timeout. + * Expected Results: QueryTimeoutException or PersistenceException + */ + public void testQueryTimeout3b() { + if (skipTests) { + return; + } + Integer setTime = new Integer(1000); + getLog().trace("testQueryTimeout3b() - setHint(" + setTime + ")"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Query q = em.createNamedQuery("NoHintSingle"); + + // verify no default javax.persistence.query.timeout is supplied + Map hints = q.getHints(); + assertFalse(hints.containsKey("javax.persistence.query.timeout")); + + // update the timeout value and verify it was set + getLog().trace("testQueryTimeout3b() - Setting hint " + + "javax.persistence.query.timeout=" + setTime); + q.setHint("javax.persistence.query.timeout", setTime); + hints = q.getHints(); + assertTrue(hints.containsKey("javax.persistence.query.timeout")); + Integer timeout = (Integer) hints.get( + "javax.persistence.query.timeout"); + assertEquals(timeout, setTime); + + try { + long startTime = System.currentTimeMillis(); + @SuppressWarnings("unused") + Object result = q.getSingleResult(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace( + "testQueryTimeout3b() - NoHintSingle runTime msecs=" + + runTime); + //assertNull("Should never get valid result due to the timeout.", result); + fail("QueryTimeout annotation failed to cause an Exception " + + "in testQueryTimeout3b(" + + setTime + " mscs), runTime msecs=" + runTime); + } catch (Exception e) { + // expected + checkException("testQueryTimeout3b()", e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Scenario being tested: 4) Timeouts < 0 are ignored and treated as the + * default no timeout scenario. + * Expected Results: The DELAY function is being called and the query + * takes 2000+ msecs to complete. + */ + public void testQueryTimeout4() { + if (skipTests) { + return; + } + Integer setTime = new Integer(-2000); + getLog().trace("testQueryTimeout4() - setHint(" + setTime + ")"); + EntityManager em = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Query q = em.createNamedQuery("NoHintSingle"); + + // verify no default javax.persistence.query.timeout is supplied + Map hints = q.getHints(); + assertFalse(hints.containsKey("javax.persistence.query.timeout")); + + // update the timeout value to -2000 and verify it was set + getLog().trace("testQueryTimeout4() - Setting hint " + + "javax.persistence.query.timeout=" + + setTime); + q.setHint("javax.persistence.query.timeout", setTime); + hints = q.getHints(); + assertTrue(hints.containsKey("javax.persistence.query.timeout")); + Integer timeout = (Integer) hints.get( + "javax.persistence.query.timeout"); + getLog().trace("testQueryTimeout4() - Retrieved hint " + + "javax.persistence.query.timeout=" + + timeout); + assertEquals(timeout, setTime); + + try { + long startTime = System.currentTimeMillis(); + Object result = q.getSingleResult(); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + getLog().trace( + "testQueryTimeout4() - NoHintSingle runTime msecs=" + + runTime); + assertTrue("Should have taken 2000+ msecs", runTime >= 2000); + assertNotNull("Verify we received a result.", result); + } catch (Exception e) { + fail("Unexpected testQueryTimeout4() exception = " + e); + } + } finally { + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Internal convenience method to execute SQL statements + * + * @param em + * @param sql + * @param timeoutSecs + * @param fail + */ + private void exec(boolean ignoreExceptions, int timeoutSecs, String sql) { + EntityManager em = null; + Statement s = null; + try { + em = emf.createEntityManager(); + assertNotNull(em); + Broker broker = JPAFacadeHelper.toBroker(em); + Connection conn = (Connection) broker.getConnection(); + s = conn.createStatement(); + if (timeoutSecs > 0) { + s.setQueryTimeout(timeoutSecs); + } + getLog().trace("execute(" + sql + ")"); + s.execute(sql); + } catch (SQLException sqe) { + if (!ignoreExceptions) { + fail(sqe.toString()); + } + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e) { + // ignore + } + } + if ((em != null) && em.isOpen()) { + em.close(); + } + } + } + + /** + * Internal convenience method for getting the OpenJPA logger + * + * @return + */ + private Log getLog() { + return emf.getConfiguration().getLog("Tests"); + } + + /** + * Internal convenience method for checking that the given Exception matches + * the expected type for a given DB platform. + * + * @param test + * @param e + */ + private void checkException(String test, Exception e) { + if (supportsQueryTimeoutException) { + assertTrue("Expected QueryTimeoutException instead of " + e, + matchesExpectedException(QueryTimeoutException.class, e)); + } else { + assertTrue("Expected PersistenceException instead of " + e, + matchesExpectedException(PersistenceException.class, e)); + } + getLog().trace(test + " - Caught expected Exception = " + e); + } + + /** + * Internal convenience method for checking that the given Exception matches + * the expected type. + * + * @param expected + * @param tested + * @return + */ + private boolean matchesExpectedException(Class expected, + Exception tested) { + assertNotNull(expected); + boolean exMatched = false; + if (tested != null) { + Class testExClass = tested.getClass(); + exMatched = expected.isAssignableFrom(testExClass); + } + return exMatched; + } + + /** + * This is the user-defined DB FUNCTION which is called from our queries to + * sleep and cause timeouts, based on seconds. + * + * @param secs + * @param value + * @return value + * @throws SQLException + */ + public static int delay(int secs, int value) throws SQLException { + try { + /* + if (value >= 0) { + System.out.println(" Native SQL called delay(secs=" + secs + + ",value=" + value + ")"); + } else { + System.out.println(" Trigger called delay(secs=" + secs + + ",value=" + value + ")"); + } + */ + Thread.sleep(secs * 1000); + } catch (InterruptedException e) { + // Ignore + } + return value; + } + + public static void main(String[] args) { + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/common/apps/QTimeout.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/common/apps/QTimeout.java new file mode 100644 index 000000000..97e878b74 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/common/apps/QTimeout.java @@ -0,0 +1,86 @@ +/* + * 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.query.common.apps; + +import java.io.Serializable; + +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedNativeQuery; +import javax.persistence.QueryHint; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "qtimeout") +@NamedNativeQueries({ +@NamedNativeQuery(name = "NoHintList", + query = "select id from qtimeout where mod(DELAY(2,id),2)=0"), +@NamedNativeQuery(name = "NoHintSingle", + query = "select id from qtimeout where mod(DELAY(2,id),2)=1"), +@NamedNativeQuery(name = "Hint0msec", + query = "select id from qtimeout where mod(DELAY(2,id),2)=0", + hints = { @QueryHint(name = "javax.persistence.query.timeout", + value = "0") }), +@NamedNativeQuery(name = "Hint1000msec", + query = "select id from qtimeout where mod(DELAY(2,id),2)=0", + hints = { @QueryHint(name = "javax.persistence.query.timeout", + value = "1000") }) +}) +public class QTimeout implements Serializable { + private static final long serialVersionUID = -622382368446668547L; + + @Id + protected int id; + + @Basic + @Column(length = 35) + protected String stringField; + + @Version + protected int versionField; + + public QTimeout() { + } + + public QTimeout(int i, String s) { + this.id = i; + this.stringField = s; + } + + public long getId() { + return id; + } + + public void setStringField(String val) { + stringField = val; + } + + public String getStringField() { + return stringField; + } + + @Override + public String toString() { + return ("id: " + id + " StringField: " + stringField); + } +} diff --git a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/query/common/apps/META-INF/persistence.xml b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/query/common/apps/META-INF/persistence.xml index 06b01c47b..6dedc0575 100644 --- a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/query/common/apps/META-INF/persistence.xml +++ b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/query/common/apps/META-INF/persistence.xml @@ -45,5 +45,6 @@ org.apache.openjpa.persistence.query.common.apps.CircularFKPC2 org.apache.openjpa.persistence.query.common.apps.ModRuntimeTest1 org.apache.openjpa.persistence.query.common.apps.ModRuntimeTest2 + org.apache.openjpa.persistence.query.common.apps.QTimeout