openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fayw...@apache.org
Subject svn commit: r756193 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-kernel/src/main/resources/org/apache/openjpa/util/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/ openjpa-persistence...
Date Thu, 19 Mar 2009 20:54:28 GMT
Author: faywang
Date: Thu Mar 19 20:54:28 2009
New Revision: 756193

URL: http://svn.apache.org/viewvc?rev=756193&view=rev
Log:
OPENJPA-963: commit patch provided by Donald Woods

Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence3.xml

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=756193&r1=756192&r2=756193&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
(original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
Thu Mar 19 20:54:28 2009
@@ -4184,7 +4184,7 @@
      * implementation of setting query and lock timeouts.
      * 
      * @param stmnt
-     * @param fetch
+     * @param fetch - optional lock and query timeouts in milliseconds
      * @param forUpdate - true if we should also try setting a lock timeout
      * @throws SQLException
      */
@@ -4210,7 +4210,7 @@
      * implementation of setting query and lock timeouts.
      * 
      * @param stmnt
-     * @param fetch
+     * @param conf - optional lock and query timeouts in milliseconds
      * @param forUpdate - true if we should also try setting a lock timeout
      * @throws SQLException
      */
@@ -4229,22 +4229,44 @@
     }
 
     /**
-     * This method is to provide override for non-JDBC or JDBC-like 
-     * implementation of setting query timeout.
+     * Provides the default validation handling of setting a query timeout.
+     * @param stmnt
+     * @param timeout in milliseconds
+     * @throws SQLException
      */
     public void setQueryTimeout(PreparedStatement stmnt, int timeout)
         throws SQLException {
-        if (supportsQueryTimeout && timeout >= 0) {
-            if (timeout > 0 && timeout < 1000) {
+        if (supportsQueryTimeout) {
+            if (timeout == -1) {
+                // special OpenJPA allowed case denoting no timeout
+                timeout = 0;
+            } else if (timeout < 0) {
+                if (log.isWarnEnabled())
+                    log.warn(_loc.get("invalid-timeout", new Integer(timeout)));
+                return;
+            } else if (timeout > 0 && timeout < 1000) {
+                // round up to 1 sec
                 timeout = 1000; 
-                Log log = conf.getLog(JDBCConfiguration.LOG_JDBC);
                 if (log.isWarnEnabled())
                     log.warn(_loc.get("millis-query-timeout"));
             }
-            stmnt.setQueryTimeout(timeout / 1000);
+            setStatementQueryTimeout(stmnt, timeout);
         }
     }
 
+    /**
+     * Allow subclasses to provide DB unique override implementations of
+     * setting query timeouts, while preserving the default timeout logic
+     * in the public setQueryTimeout method.
+     * @param stmnt
+     * @param timeout in milliseconds
+     * @throws SQLException
+     */
+    protected void setStatementQueryTimeout(PreparedStatement stmnt, 
+        int timeout) throws SQLException {
+        // JDBC uses seconds, so we'll do a simple round-down conversion here
+        stmnt.setQueryTimeout(timeout / 1000);
+    }
 
     //////////////////////////////////////
     // ConnectionDecorator implementation

Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties?rev=756193&r1=756192&r2=756193&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties
(original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties
Thu Mar 19 20:54:28 2009
@@ -75,3 +75,5 @@
 	abstract class "{0}".
 query-failed: A query statement timeout has occurred.
 query-timeout: A query statement timeout (set to {0} milliseconds) has occurred.
+invalid-timeout: An invalid timeout of {0} milliseconds was ignored.  \
+        Expected a value that is greater than or equal to zero.

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java?rev=756193&r1=756192&r2=756193&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java
(original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java
Thu Mar 19 20:54:28 2009
@@ -16,18 +16,24 @@
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import javax.persistence.EntityManager;
 import javax.persistence.Query;
 
+import org.apache.openjpa.conf.OpenJPAConfiguration;
 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.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.persistence.OpenJPAQuery;
 import org.apache.openjpa.persistence.PersistenceException;
 import org.apache.openjpa.persistence.QueryTimeoutException;
 import org.apache.openjpa.persistence.query.common.apps.QTimeout;
@@ -36,14 +42,38 @@
 
 /**
  * Tests the new query timeout hint support in the JPA 2.0 spec.
+ * Query timeout scenarios being tested:
+ *   1) By default, there is no timeout
+ *   2) Setting timeout to 0 is same as no timeout (JDBC defined)
+ *     2.1) using Map properties on createEMF (or PU properties)
+ *     2.2) using the QueryHint annotation
+ *     2.3) using setHint()
+ *   3) Setting timeout to msecs < DELAY value causes new 
+ *      javax.persistence.QueryTimeoutException for databases that do not
+ *      cause a rollback or a PersistenceException if they do, when set by:
+ *     3.1) using persistence.xml PU properties (or createEMF Map properties)
+ *     3.2) using the QueryHint annotation
+ *     3.3) calling setHint()
+ * Query 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
+ *   5) Updates after EM.find()/findAll() are not affected by query timeout
+ * 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
  * 
  * @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() {
@@ -57,20 +87,24 @@
         // 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;
+        if (dict.supportsQueryTimeout) {
+            if (!(dict instanceof DerbyDictionary)) {
+                // 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("FIXME - TestQueryTimeout tests are being " +
+                    "skipped, as tests are not being run against a Derby DB.");
+                skipTests = true;
+            }
         } 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.");
+            getLog().info("TestQueryTimeout tests are being skipped, " +
+                "due to DB not supporting Query Timeouts.");
             skipTests = true;
-            return;
         }
+        if (skipTests)
+            return;
 
+        // create some initial entities
         try {
             em = emf.createEntityManager();
             assertNotNull(em);
@@ -89,53 +123,50 @@
             }
         }
 
-        // execute some native SQL with no timeouts
+        // create delay function only on Derby, other DBs require manual setup
         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
-     */
+            getLog().trace("setUp() - creating DELAY function only for " +
+                "Derby.  Other DBs require manual setup.");
+            // remove existing function if it exists and recreate
+            try {
+                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'");
+            } catch (SQLException sqe) {
+                fail(sqe.toString());
+            }
+        }
+        
+        // create triggers on all DBs
+        try {
+            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)");
+        } catch (SQLException sqe) {
+            if (dict instanceof DerbyDictionary) {
+                // Always fail if we couldn't create triggers in Derby
+                fail(sqe.toString());
+            } else {
+                // just disable tests for other DBs
+                getLog().info("TestQueryTimeout tests are being skipped, " +
+                    "due to DB delay() function missing and/or problems " +
+                    "creating the required triggers.  DBs other than " +
+                    "Derby require manual setup steps for these tests.");
+                skipTests = true;
+                return;
+            }
+        }
+    }
 
     /**
      * Scenario being tested: 1a) By default, there is no timeout for queries.
@@ -186,29 +217,29 @@
         if (skipTests) {
             return;
         }
-        getLog().trace("testQueryTimeout1c() - No Update timeout");
+        getLog().trace("testQueryTimeout1c() - No executeUpdate timeout");
         EntityManager em = null;
         try {
             em = emf.createEntityManager();
             assertNotNull(em);
+            Query q = em.createQuery("UPDATE QTimeout q SET q.stringField = :strVal WHERE
q.id = 1");
+            q.setParameter("strVal", new String("updated"));
+            // verify no default javax.persistence.query.timeout is supplied
+            Map<String, Object> hints = q.getHints();
+            assertFalse(hints.containsKey("javax.persistence.query.timeout"));
             try {
                 long startTime = System.currentTimeMillis();
-                QTimeout qt = em.find(QTimeout.class, new Integer(1));
                 em.getTransaction().begin();
-                qt.setStringField("updated");
-                em.flush();
+                int count = q.executeUpdate();
                 em.getTransaction().commit();
                 long endTime = System.currentTimeMillis();
                 long runTime = endTime - startTime;
-                getLog().trace("testQueryTimeout1c() - EM find/update runTime" +
-                    " msecs=" + runTime);
+                getLog().trace("testQueryTimeout1c() - executeUpdate runTime " + 
+                    "msecs=" + runTime);
+                assertTrue("Verify we received one result.", (count == 1));
                 // Hack - Windows sometimes returns 1999 instead of 2000+
                 assertTrue("Should have taken 2+ secs, but was msecs=" +
                     runTime, runTime > 1900);
-                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);
             }
@@ -220,16 +251,76 @@
     }
 
     /**
-     * Scenario being tested: 2.1.a) Explicit annotated QueryHint of timeout=0
+     * Scenario being tested: 2.1.b) Explicit Map of properties to createEMF
+     * with timeout=0 is treated the same as the default no query timeout.
+     * Expected Results: The DELAY function is being called and the query
+     * takes 2000+ msecs to complete.
+     */
+    public void testQueryTimeout21b() {
+        if (skipTests) {
+            return;
+        }
+        getLog().trace("testQueryTimeout21b() - Map(timeout=0)");
+        OpenJPAEntityManagerFactory emf = null;
+        OpenJPAEntityManager em = null;
+        Integer setTime = new Integer(0);
+        // create the Map to test overrides
+        Map<String,String >props = new HashMap<String,String>();
+        props.put("javax.persistence.query.timeout", "0");
+        
+        try {
+            // create our EMF with our timeout property
+            emf = OpenJPAPersistence.createEntityManagerFactory(
+                "qtimeout-no-properties", "persistence3.xml", props);
+            assertNotNull(emf);
+            // verify Map properties updated the config
+            OpenJPAConfiguration conf = emf.getConfiguration();
+            assertNotNull(conf);
+            assertEquals("Map provided query timeout", setTime.intValue(),
+                conf.getQueryTimeout());
+            // verify no default javax.persistence.query.timeout is supplied
+            // as the Map properties are not passed through as hints
+            em = emf.createEntityManager();
+            assertNotNull(em);
+            OpenJPAQuery q = em.createNamedQuery("NoHintSingle");
+            Map<String, Object> hints = q.getHints();
+            assertFalse(hints.containsKey("javax.persistence.query.timeout"));
+            // verify internal config values were updated
+            assertEquals("Map provided query timeout", setTime.intValue(),
+                q.getFetchPlan().getQueryTimeout());
+            
+            try {
+                long startTime = System.currentTimeMillis();
+                Object result = q.getSingleResult();
+                long endTime = System.currentTimeMillis();
+                long runTime = endTime - startTime;
+                getLog().trace("testQueryTimeout21b() - NoHintSingle runTime " + 
+                    "msecs=" + runTime);
+                // Hack - Windows sometimes returns 1999 instead of 2000+
+                assertTrue("Should have taken 2+ secs, but was msecs=" +
+                    runTime, runTime > 1900);
+                assertNotNull("Verify we received a result.", result);
+            } catch (Exception e) {
+                fail("Unexpected testQueryTimeout21b() exception = " + e);
+            }
+        } finally {
+            if ((em != null) && em.isOpen()) {
+                em.close();
+            }
+        }
+    }
+
+    /**
+     * Scenario being tested: 2.2.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.
      */
-    public void testQueryTimeout2a() {
+    public void testQueryTimeout22a() {
         if (skipTests) {
             return;
         }
-        getLog().trace("testQueryTimeout2a() - QueryHint=0");
+        getLog().trace("testQueryTimeout22a() - QueryHint=0");
         EntityManager em = null;
         try {
             em = emf.createEntityManager();
@@ -240,7 +331,7 @@
             assertTrue(hints.containsKey("javax.persistence.query.timeout"));
             Integer timeout = new Integer(
                 (String) hints.get("javax.persistence.query.timeout"));
-            getLog().trace("testQueryTimeout2a() - Retrieved hint " + 
+            getLog().trace("testQueryTimeout22a() - Retrieved hint " + 
                 "javax.persistence.query.timeout=" + timeout);
             assertEquals(timeout, new Integer(0));
 
@@ -250,14 +341,14 @@
                 List results = q.getResultList();
                 long endTime = System.currentTimeMillis();
                 long runTime = endTime - startTime;
-                getLog().trace("testQueryTimeout2a() - Hint0msec runTime msecs="
+                getLog().trace("testQueryTimeout22a() - Hint0msec runTime msecs="
                     + runTime);
                 // Hack - Windows sometimes returns 5999 instead of 6000+
                 assertTrue("Should have taken 6+ secs, but was msecs=" +
                     runTime, runTime > 5900);
                 assertEquals("Verify we found 2 results.", 2, results.size());
             } catch (Exception e) {
-                fail("Unexpected testQueryTimeout2a() exception = " + e);
+                fail("Unexpected testQueryTimeout22a() exception = " + e);
             }
         } finally {
             if ((em != null) && em.isOpen()) {
@@ -267,17 +358,17 @@
     }
 
     /**
-     * Scenario being tested: 2.1.b) Explicit setHint of timeout=0 is treated
+     * Scenario being tested: 2.3.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() {
+    public void testQueryTimeout23b() {
         if (skipTests) {
             return;
         }
         Integer setTime = new Integer(0);
-        getLog().trace("testQueryTimeout2b() - setHint(" + setTime + ")");
+        getLog().trace("testQueryTimeout23b() - setHint(" + setTime + ")");
         EntityManager em = null;
         try {
             em = emf.createEntityManager();
@@ -289,14 +380,14 @@
             assertFalse(hints.containsKey("javax.persistence.query.timeout"));
 
             // update the timeout value to 0 and verify it was set
-            getLog().trace("testQueryTimeout2b() - Setting hint " + 
+            getLog().trace("testQueryTimeout23b() - 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 " +
+            getLog().trace("testQueryTimeout23b() - Retrieved hint " +
                 "javax.persistence.query.timeout=" + timeout);
             assertEquals(timeout, setTime);
 
@@ -305,14 +396,14 @@
                 Object result = q.getSingleResult();
                 long endTime = System.currentTimeMillis();
                 long runTime = endTime - startTime;
-                getLog().trace("testQueryTimeout2b() - NoHintSingle runTime " + 
+                getLog().trace("testQueryTimeout23b() - NoHintSingle runTime " + 
                     "msecs=" + runTime);
                 // Hack - Windows sometimes returns 1999 instead of 2000+
                 assertTrue("Should have taken 2+ secs, but was msecs=" +
                     runTime, runTime > 1900);
                 assertNotNull("Verify we received a result.", result);
             } catch (Exception e) {
-                fail("Unexpected testQueryTimeout2b() exception = " + e);
+                fail("Unexpected testQueryTimeout23b() exception = " + e);
             }
         } finally {
             if ((em != null) && em.isOpen()) {
@@ -322,32 +413,114 @@
     }
 
     /**
-     * Scenario being tested: 3.1.a) Explicit annotated QueryHint of
-     * timeout=1000 msecs will cause the query to timeout.
-     * Expected Results: QueryTimeoutException or PersistenceException
+     * Scenario being tested: 3.1.c) Explicit persistence.xml provided PU
+     * property of timeout=1000 msecs will cause the query to timeout.
+     * Expected Results: The DELAY function is being called and the query
+     * takes 2000+ msecs to complete.
      */
-    public void testQueryTimeout3a() {
+    public void testQueryTimeout31c() {
         if (skipTests) {
             return;
         }
+        getLog().trace("testQueryTimeout31c() - PU(timeout=1000), executeUpdate timeout");
+        OpenJPAEntityManagerFactory emf = null;
+        OpenJPAEntityManager em = null;
         Integer setTime = new Integer(1000);
-        getLog().trace("testQueryTimeout3a() - QueryHint(" + setTime + ")");
-        EntityManager em = null;
+
         try {
+            // create our EMF with our PU set timeout property
+            emf = OpenJPAPersistence.createEntityManagerFactory(
+                "qtimeout-1000msecs", "persistence3.xml");
+            assertNotNull(emf);
+            // verify PU properties updated the config
+            OpenJPAConfiguration conf = emf.getConfiguration();
+            assertNotNull(conf);
+            assertEquals("PU provided query timeout", setTime.intValue(),
+                conf.getQueryTimeout());
+            // create EM and Query
             em = emf.createEntityManager();
             assertNotNull(em);
-            Query q = em.createNamedQuery("Hint1000msec");
+            OpenJPAQuery q = em.createNativeQuery("UPDATE QTimeout SET stringField = ? WHERE
mod(DELAY(2,id),2)=0");
+            q.setParameter(1, new String("updated"));
+            // verify no default javax.persistence.query.timeout is supplied
+            Map<String, Object> hints = q.getHints();
+            assertFalse(hints.containsKey("javax.persistence.query.timeout"));
+            // verify internal config values were updated
+            assertEquals("PU provided query timeout", setTime.intValue(),
+                q.getFetchPlan().getQueryTimeout());
 
+            // verify queryTimeout on EM find operations
+            try {
+                long startTime = System.currentTimeMillis();
+                em.getTransaction().begin();
+                int count = q.executeUpdate();
+                em.getTransaction().commit();
+                long endTime = System.currentTimeMillis();
+                long runTime = endTime - startTime;
+                getLog().trace("testQueryTimeout31c() - executeUpdate runTime " + 
+                    "msecs=" + runTime);
+                fail("QueryTimeout for executeUpdate failed to cause an " + 
+                    "Exception in testQueryTimeout31c(" + setTime +
+                    " mscs), runTime msecs=" + runTime);
+            } catch (Exception e) {
+                // expected - Should cause a QueryTimeoutException for Derby
+                checkException("testQueryTimeout31c()", e);
+            }
+        } finally {
+            if ((em != null) && em.isOpen()) {
+                if (em.getTransaction().isActive())
+                    em.getTransaction().rollback();
+                em.close();
+            }
+        }
+    }
+
+    /**
+     * Scenario being tested: 3.2.a) Explicit annotated QueryHint of
+     * timeout=1000 msecs will override the PU and Map provided timeouts
+     * and cause the query to timeout.
+     * Expected Results: QueryTimeoutException or PersistenceException
+     */
+    public void testQueryTimeout32a() {
+        if (skipTests) {
+            return;
+        }
+        getLog().trace("testQueryTimeout32a() - PU(1000), Map(0), QueryHint(1000)");
+        OpenJPAEntityManagerFactory emf = null;
+        OpenJPAEntityManager em = null;
+        Integer setTime = new Integer(0);
+        // create the Map to test overrides
+        Map<String,String> props = new HashMap<String,String>();
+        props.put("javax.persistence.query.timeout", "0");
+        
+        try {
+            // create our EMF with our PU set timeout property
+            emf = OpenJPAPersistence.createEntityManagerFactory(
+                "qtimeout-1000msecs", "persistence3.xml", props);
+            assertNotNull(emf);
+            // verify Map properties overrode the PU properties in config
+            OpenJPAConfiguration conf = emf.getConfiguration();
+            assertNotNull(conf);
+            assertEquals("Map provided query timeout", setTime.intValue(),
+                conf.getQueryTimeout());
+            // create EM and named query
+            em = emf.createEntityManager();
+            assertNotNull(em);
+            OpenJPAQuery q = em.createNamedQuery("Hint1000msec");
+            setTime = 1000;
             // verify javax.persistence.query.timeout hint via annotation set
             Map<String, Object> 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="
+                "testQueryTimeout32a() - Found javax.persistence.query.timeout="
                 + timeout);
             assertTrue("Expected to find a javax.persistence.query.timeout="
                 + setTime, (timeout.intValue() == setTime.intValue()));
+            // verify internal config values were updated
+            assertEquals("QueryHint provided query timeout", setTime.intValue(),
+                q.getFetchPlan().getQueryTimeout());
 
             try {
                 long startTime = System.currentTimeMillis();
@@ -356,16 +529,16 @@
                 long endTime = System.currentTimeMillis();
                 long runTime = endTime - startTime;
                 getLog().trace(
-                    "testQueryTimeout3a() - Hint1000msec runTime msecs="
+                    "testQueryTimeout32a() - 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 +
+                    "in testQueryTimeout32a(" + setTime +
                     " msecs), runTime msecs=" + runTime);
             } catch (Exception e) {
                 // expected
-                checkException("testQueryTimeout3a()", e);
+                checkException("testQueryTimeout32a()", e);
             }
         } finally {
             if ((em != null) && em.isOpen()) {
@@ -375,16 +548,16 @@
     }
 
     /**
-     * Scenario being tested: 3.2.b) Explicit setHint of timeout to 1000 msecs
+     * Scenario being tested: 3.3.b) Explicit setHint of timeout to 1000 msecs
      * will cause the query to timeout.
      * Expected Results: QueryTimeoutException or PersistenceException
      */
-    public void testQueryTimeout3b() {
+    public void testQueryTimeout33b() {
         if (skipTests) {
             return;
         }
         Integer setTime = new Integer(1000);
-        getLog().trace("testQueryTimeout3b() - setHint(" + setTime + ")");
+        getLog().trace("testQueryTimeout33b() - setHint(" + setTime + ")");
         EntityManager em = null;
         try {
             em = emf.createEntityManager();
@@ -396,7 +569,7 @@
             assertFalse(hints.containsKey("javax.persistence.query.timeout"));
 
             // update the timeout value and verify it was set
-            getLog().trace("testQueryTimeout3b() - Setting hint " +
+            getLog().trace("testQueryTimeout33b() - Setting hint " +
                 "javax.persistence.query.timeout=" + setTime);
             q.setHint("javax.persistence.query.timeout", setTime);
             hints = q.getHints();
@@ -412,15 +585,15 @@
                 long endTime = System.currentTimeMillis();
                 long runTime = endTime - startTime;
                 getLog().trace(
-                    "testQueryTimeout3b() - NoHintSingle runTime msecs="
+                    "testQueryTimeout33b() - 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 +
+                    "in testQueryTimeout33b(" + setTime +
                     " mscs), runTime msecs=" + runTime);
             } catch (Exception e) {
                 // expected
-                checkException("testQueryTimeout3b()", e);
+                checkException("testQueryTimeout33b()", e);
             }
         } finally {
             if ((em != null) && em.isOpen()) {
@@ -430,6 +603,85 @@
     }
 
     /**
+     * Scenario being tested: 3.3.c) Explicit setHint of timeout to 1000 msecs
+     * will cause the PU provided timeout=0 value to be overridden and the
+     * executeUpdate to timeout.
+     * Expected Results: QueryTimeoutException (Derby) or PersistenceException
+     */
+    public void testQueryTimeout33c() {
+        if (skipTests) {
+            return;
+        }
+        getLog().trace("testQueryTimeout33c() - PU(timeout=0), setHint(1000), executeUpdate
timeout");
+        OpenJPAEntityManagerFactory emf = null;
+        OpenJPAEntityManager em = null;
+        Integer setTime = new Integer(0);        
+
+        try {
+            // create our EMF with our PU set timeout property
+            emf = OpenJPAPersistence.createEntityManagerFactory(
+                "qtimeout-0msecs", "persistence3.xml");
+            assertNotNull(emf);
+            // verify PU properties updated the config
+            OpenJPAConfiguration conf = emf.getConfiguration();
+            assertNotNull(conf);
+            assertEquals("PU provided no query timeout", setTime.intValue(),
+                conf.getQueryTimeout());
+            // create EM and Query
+            em = emf.createEntityManager();
+            assertNotNull(em);
+            // Following fails to cause a SQLException, but takes 2+ secs
+            // Query q = em.createQuery("UPDATE QTimeout q SET q.stringField = :strVal WHERE
q.id > 0");
+            // q.setParameter("strVal", new String("updated"));
+            // Following fails to cause a SQLException, but takes 2+ secs
+            // Query q = em.createNativeQuery("INSERT INTO QTimeout (id, stringField) VALUES
(?,?)");
+            // q.setParameter(1, 99);
+            // q.setParameter(2, new String("inserted"));
+            OpenJPAQuery q = em.createNativeQuery("UPDATE QTimeout SET stringField = ? WHERE
mod(DELAY(2,id),2)=0");
+            q.setParameter(1, new String("updated"));
+            // verify no default javax.persistence.query.timeout is supplied
+            Map<String, Object> hints = q.getHints();
+            assertFalse(hints.containsKey("javax.persistence.query.timeout"));          
 
+            // update the query timeout value and verify it was set
+            setTime = 1000;
+            getLog().trace("testQueryTimeout33c() - 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);
+            // verify internal config values were updated
+            assertEquals("PU provided query timeout", setTime.intValue(),
+                q.getFetchPlan().getQueryTimeout());
+            
+            try {
+                long startTime = System.currentTimeMillis();
+                em.getTransaction().begin();
+                int count = q.executeUpdate();
+                em.getTransaction().commit();
+                long endTime = System.currentTimeMillis();
+                long runTime = endTime - startTime;
+                getLog().trace("testQueryTimeout33c() - executeUpdate runTime " + 
+                    "msecs=" + runTime);
+                fail("QueryTimeout for executeUpdate failed to cause an " + 
+                    "Exception in testQueryTimeout33c(" + setTime +
+                    " mscs), runTime msecs=" + runTime);
+            } catch (Exception e) {
+                // expected - Should cause a QueryTimeoutException for Derby
+                checkException("testQueryTimeout33c()", e);
+            }
+        } finally {
+            if ((em != null) && em.isOpen()) {
+                if (em.getTransaction().isActive())
+                    em.getTransaction().rollback();
+                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
@@ -488,6 +740,65 @@
     }
 
     /**
+     * Scenario being tested: 5) PU Query timeout hints do not affect EM
+     * operations like updating Entities returned by EM.find()/findAll()
+     * Expected Results: The DELAY function is being called and the update
+     * takes 2000+ msecs to complete.
+     */
+    public void testQueryTimeout5() {
+        if (skipTests) {
+            return;
+        }
+        getLog().trace("testQueryTimeout5() - No EM.find() update timeout");
+        OpenJPAEntityManagerFactory emf = null;
+        OpenJPAEntityManager em = null;
+        Integer setTime = new Integer(1000);
+        
+        try {
+            // create our EMF with our PU set timeout property
+            emf = OpenJPAPersistence.createEntityManagerFactory(
+                "qtimeout-1000msecs", "persistence3.xml");
+            assertNotNull(emf);
+            // verify PU properties updated the config
+            OpenJPAConfiguration conf = emf.getConfiguration();
+            assertNotNull(conf);
+            assertEquals("PU provided timeout", setTime.intValue(),
+                conf.getQueryTimeout());
+            // create EM
+            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("testQueryTimeout1d() - EM find/update runTime" +
+                    " msecs=" + runTime);
+                // Hack - Windows sometimes returns 1999 instead of 2000+
+                assertTrue("Should have taken 2+ secs, but was msecs=" +
+                    runTime, runTime > 1900);
+                em.clear();
+                qt = em.find(QTimeout.class, new Integer(1));
+                assertEquals("Verify the entity was updated.",
+                    qt.getStringField(), "updated");
+            } catch (Exception e) {
+                // setting a timeout property via PU or Map shouldn't cause a
+                // timeout exception
+                fail("Unexpected testQueryTimeout5() exception = " + e);
+            }
+        } finally {
+            if ((em != null) && em.isOpen()) {
+                em.close();
+            }
+        }
+    }
+
+    /**
      * Internal convenience method to execute SQL statements
      * 
      * @param em
@@ -495,7 +806,8 @@
      * @param timeoutSecs
      * @param fail
      */
-    private void exec(boolean ignoreExceptions, int timeoutSecs, String sql) {
+    private void exec(boolean ignoreExceptions, int timeoutSecs, String sql)
+        throws SQLException {
         EntityManager em = null;
         Statement s = null;
         try {
@@ -511,7 +823,8 @@
             s.execute(sql);
         } catch (SQLException sqe) {
             if (!ignoreExceptions) {
-                fail(sqe.toString());
+                // fail(sqe.toString());
+                throw sqe;
             }
         } finally {
             if (s != null) {
@@ -544,13 +857,10 @@
      * @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));
-        }
+        // no easy way to determine exact Exception type for all DBs
+        assertTrue(test + " - UNEXPECTED Exception = " + e,
+            matchesExpectedException(QueryTimeoutException.class, e) ||
+            matchesExpectedException(PersistenceException.class, e));
         getLog().trace(test + " - Caught expected Exception = " + e);
     }
 
@@ -569,6 +879,11 @@
         if (tested != null) {
             Class<?> testExClass = tested.getClass();
             exMatched = expected.isAssignableFrom(testExClass);
+            if (exMatched) {
+                // make sure it is our expected exception text from
+                // localizer.properties
+                exMatched = (tested.getMessage().indexOf("query statement timeout") != -1);
+            }
         }
         return exMatched;
     }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence3.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence3.xml?rev=756193&r1=756192&r2=756193&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence3.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence3.xml Thu
Mar 19 20:54:28 2009
@@ -21,11 +21,11 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     version="1.0">
     
-    <!-- Following 2 PUs are used by TestQueryProperties -->
+    <!-- Following PUs are used by TestQueryProperties and TestQueryTimeout -->
     <persistence-unit name="qtimeout-no-properties">
     	<class>org.apache.openjpa.persistence.query.common.apps.QTimeout</class>
     </persistence-unit>
-    
+
     <persistence-unit name="qtimeout-with-properties">
     	<class>org.apache.openjpa.persistence.query.common.apps.QTimeout</class>
         <properties>
@@ -34,7 +34,13 @@
         </properties>
     </persistence-unit>
     
-    <!-- Following PU is used by TestQueryTimeout -->
+    <persistence-unit name="qtimeout-0msecs">
+    	<class>org.apache.openjpa.persistence.query.common.apps.QTimeout</class>
+        <properties>
+            <property name="javax.persistence.query.timeout" value="0"/>
+        </properties>
+    </persistence-unit>
+
     <persistence-unit name="qtimeout-1000msecs">
     	<class>org.apache.openjpa.persistence.query.common.apps.QTimeout</class>
         <properties>



Mime
View raw message