You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by jr...@apache.org on 2011/02/08 17:42:22 UTC

svn commit: r1068472 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-persistence-jdbc/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/ openjpa-persistence-locking/ openjpa-persistence-loc...

Author: jrbauer
Date: Tue Feb  8 16:42:22 2011
New Revision: 1068472

URL: http://svn.apache.org/viewvc?rev=1068472&view=rev
Log:
OPENJPA-1935 Updated Informix dictionary to examine nested SQL exceptions when determining whether a generic exception is a lock exception.  Added Informix JDBC profile to jdbc and locking poms.

Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/InformixDictionary.java
    openjpa/trunk/openjpa-persistence-jdbc/pom.xml
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java
    openjpa/trunk/openjpa-persistence-locking/pom.xml
    openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/InformixDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/InformixDictionary.java?rev=1068472&r1=1068471&r2=1068472&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/InformixDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/InformixDictionary.java Tue Feb  8 16:42:22 2011
@@ -27,6 +27,8 @@ import java.sql.Statement;
 import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.openjpa.jdbc.identifier.DBIdentifier;
 import org.apache.openjpa.jdbc.identifier.DBIdentifier.DBIdentifierType;
@@ -393,12 +395,61 @@ public class InformixDictionary
         // SQL State of IX000 is a general purpose Informix error code
         // category, so only return Boolean.TRUE if we match SQL Codes
         // recoverable = Boolean.FALSE;
-        if ((subtype == StoreException.LOCK && ex.getErrorCode() == -154) 
+        if ((subtype == StoreException.LOCK && checkNestedErrorCodes(ex, "IX000", -154)) 
           ||(subtype == StoreException.QUERY && ex.getErrorCode() == -213)) {
             return false;
         }
         
         return super.isFatalException(subtype, ex);
     }
+
+    /**
+     * Specialized matchErrorState method for Informix.  Informix exceptions are
+     * typically nested multiple levels deep.  Correct determination of the exception type requires
+     * inspection of nested exceptions to determine the root cause. A list of Informix (IDS v10) error codes
+     * can be found here:
+     * 
+     * http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.em.doc/errors_ids100.html
+     * 
+     * @param errorStates classification of SQL error states by their specific nature. The keys of the
+     * map represent one of the constants defined in {@link StoreException}. The value corresponding to
+     * a key represent the set of SQL Error States representing specific category of database error. 
+     * This supplied map is sourced from <code>sql-error-state-codes.xml</xml> and filtered the
+     * error states for the current database.
+     * 
+     * @param ex original SQL Exception as raised by the database driver.
+     * 
+     * @return A constant indicating the category of error as defined in {@link StoreException}.
+     */
+    protected int matchErrorState(Map<Integer,Set<String>> errorStates, SQLException ex) {
+        // Informix SQLState IX000 is a general SQLState that applies to many possible conditions
+        // If the underlying cause is also an IX000 with error code: 
+        // -107 ISAM error: record is locked. || -154 ISAM error: Lock Timeout Expired.
+        // the exception type is LOCK.
+        if (checkNestedErrorCodes(ex, "IX000", -107, -154)) {
+           return StoreException.LOCK;
+        }
+        return super.matchErrorState(errorStates, ex);
+    }
+    
+    private boolean checkNestedErrorCodes(SQLException ex, String sqlState, int...errorCodes) {
+        SQLException cause = ex;
+        int level = 0;
+        // Query at most 5 exceptions deep to prevent infinite iteration exception loops
+        // Typically, the root exception is at level 3.
+        while (cause != null && level < 5) {
+            String errorState = cause.getSQLState();
+            if (sqlState == null || sqlState.equals(errorState)) {
+                for (int ec : errorCodes) {
+                    if (cause.getErrorCode() == ec) {
+                        return true;
+                    }
+                }
+            }
+            cause = cause.getNextException();
+            level++;
+        }
+        return false;
+    }
 }
 

Modified: openjpa/trunk/openjpa-persistence-jdbc/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/pom.xml?rev=1068472&r1=1068471&r2=1068472&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/pom.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/pom.xml Tue Feb  8 16:42:22 2011
@@ -627,6 +627,74 @@
             </repositories>
         </profile>
 
+        <!-- Profile for testing Informix with the Informix JDBC Driver -->
+        <profile>
+            <!--
+                Example Informix profile. You can use this profile if you:
+                1) have the Informix JDBC artifacts installed in a local repo and 
+                supply the URL:
+                  -Dids.maven.repo=http://my.local.repo
+                2) have a copy of the Informix driver and run the following
+                commands :
+                    mvn install:install-file -Dfile=${path to ifxjdbc.jar} \
+                                             -DgroupId=com.informix \
+                                             -DartifactId=informix-driver \ 
+                                             -Dversion=3.70 \
+                                             -Dpackaging=jar
+
+                You must also set the following properties:
+                    -Dopenjpa.ids.url=jdbc:informix-sqli://<HOST>:<PORT>:informixserver=<INFORMIXSERVER>;database=<DBNAME>
+                    -Dopenjpa.ids.username=<ids_uid>
+                    -Dopenjpa.ids.password=<ids_pwd>
+
+                Optionally, you can override the default Informix groupId,
+                artifactIds and version by also supplying the following
+                properties:
+                    -Dids.groupid=com.informix
+                    -Dids.driver.artifactid=informix-driver
+                    -Dids.version=3.70
+            -->
+            <id>test-ids-informix</id>
+            <activation>
+                <property>
+                    <name>test-ids-informix</name>
+                </property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>${ids.groupid}</groupId>
+                    <artifactId>${ids.driver.artifactid}</artifactId>
+                    <version>${ids.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <properties>
+                <ids.maven.repo>http://not.a.real.repository</ids.maven.repo>
+                <ids.groupid>com.informix</ids.groupid>
+                <ids.driver.artifactid>informix-driver</ids.driver.artifactid>
+                <ids.version>3.70</ids.version>
+                <connection.driver.name>com.informix.jdbc.IfxDriver</connection.driver.name>
+                <connection.url>${openjpa.ids.url}</connection.url>
+                <connection.username>${openjpa.ids.username}</connection.username>
+                <connection.password>${openjpa.ids.password}</connection.password>
+            </properties>
+            <repositories>
+                <repository>
+                    <id>ids.repository</id>
+                    <name>Informix Repository</name>
+                    <url>${ids.maven.repo}</url>
+                    <layout>default</layout>
+                    <snapshots>
+                        <enabled>false</enabled>
+                    </snapshots>
+                    <releases>
+                        <enabled>true</enabled>
+                        <checksumPolicy>ignore</checksumPolicy>
+                    </releases>
+                </repository>
+            </repositories>
+        </profile>
+        
         <!-- Profile for testing with Oracle DB -->
         <profile>
             <!--

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java?rev=1068472&r1=1068471&r2=1068472&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java Tue Feb  8 16:42:22 2011
@@ -222,6 +222,16 @@ public abstract class SQLListenerTestCas
     	return buf.toString();
     }
 
+    /**
+     * Returns the last SQL executed or the empty string if the list is
+     * empty.
+    */ 
+    public String getLastSQL(List<String> list) {
+        if (list != null && list.size() > 0)
+            return list.get(list.size() -1);
+        return "";
+    }
+
     public enum SQLAssertType {
         SQL, NotSQL, ContainsSQL, AllSQLInOrder, AllExactSQLInOrder, 
         AllSQLAnyOrder, NoneSQLAnyOrder, AnySQLAnyOrder

Modified: openjpa/trunk/openjpa-persistence-locking/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-locking/pom.xml?rev=1068472&r1=1068471&r2=1068472&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-locking/pom.xml (original)
+++ openjpa/trunk/openjpa-persistence-locking/pom.xml Tue Feb  8 16:42:22 2011
@@ -594,6 +594,74 @@
             </repositories>
         </profile>
 
+        <!-- Profile for testing Informix with the Informix JDBC Driver -->
+        <profile>
+            <!--
+                Example Informix profile. You can use this profile if you:
+                1) have the Informix JDBC artifacts installed in a local repo and 
+                supply the URL:
+                  -Dids.maven.repo=http://my.local.repo
+                2) have a copy of the Informix driver and run the following
+                commands :
+                    mvn install:install-file -Dfile=${path to ifxjdbc.jar} \
+                                             -DgroupId=com.informix \
+                                             -DartifactId=informix-driver \ 
+                                             -Dversion=3.70 \
+                                             -Dpackaging=jar
+
+                You must also set the following properties:
+                    -Dopenjpa.ids.url=jdbc:informix-sqli://<HOST>:<PORT>:informixserver=<INFORMIXSERVER>;database=<DBNAME>
+                    -Dopenjpa.ids.username=<ids_uid>
+                    -Dopenjpa.ids.password=<ids_pwd>
+
+                Optionally, you can override the default Informix groupId,
+                artifactIds and version by also supplying the following
+                properties:
+                    -Dids.groupid=com.informix
+                    -Dids.driver.artifactid=informix-driver
+                    -Dids.version=3.70
+            -->
+            <id>test-ids-informix</id>
+            <activation>
+                <property>
+                    <name>test-ids-informix</name>
+                </property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>${ids.groupid}</groupId>
+                    <artifactId>${ids.driver.artifactid}</artifactId>
+                    <version>${ids.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <properties>
+                <ids.maven.repo>http://not.a.real.repository</ids.maven.repo>
+                <ids.groupid>com.informix</ids.groupid>
+                <ids.driver.artifactid>informix-driver</ids.driver.artifactid>
+                <ids.version>3.70</ids.version>
+                <connection.driver.name>com.informix.jdbc.IfxDriver</connection.driver.name>
+                <connection.url>${openjpa.ids.url}</connection.url>
+                <connection.username>${openjpa.ids.username}</connection.username>
+                <connection.password>${openjpa.ids.password}</connection.password>
+            </properties>
+            <repositories>
+                <repository>
+                    <id>ids.repository</id>
+                    <name>Informix Repository</name>
+                    <url>${ids.maven.repo}</url>
+                    <layout>default</layout>
+                    <snapshots>
+                        <enabled>false</enabled>
+                    </snapshots>
+                    <releases>
+                        <enabled>true</enabled>
+                        <checksumPolicy>ignore</checksumPolicy>
+                    </releases>
+                </repository>
+            </repositories>
+        </profile>
+        
         <!-- Profile for testing with Oracle DB -->
         <profile>
             <!-- 

Modified: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java?rev=1068472&r1=1068471&r2=1068472&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java (original)
+++ openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java Tue Feb  8 16:42:22 2011
@@ -40,6 +40,7 @@ import org.apache.openjpa.jdbc.conf.JDBC
 import org.apache.openjpa.jdbc.sql.DB2Dictionary;
 import org.apache.openjpa.jdbc.sql.DBDictionary;
 import org.apache.openjpa.jdbc.sql.DerbyDictionary;
+import org.apache.openjpa.jdbc.sql.InformixDictionary;
 import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.persistence.LockTimeoutException;
 import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
@@ -396,14 +397,14 @@ public class TestPessimisticLocks extend
         String firstName1 = (String) q1.getSingleResult();
         //Expected sql for Derby is:
         //SELECT t0.firstName FROM Employee t0 WHERE (t0.id = CAST(? AS BIGINT)) FOR UPDATE WITH RR
-        String SQL1 = toString(sql);
+        String SQL1 = getLastSQL(sql);
         
         // run the second time
         resetSQL();
         Query q2 = em.createQuery(jpql);
         q2.setLockMode(LockModeType.PESSIMISTIC_WRITE);
         String firstName2 = (String) q2.getSingleResult();
-        String SQL2 = toString(sql);
+        String SQL2 = getLastSQL(sql);
         assertEquals(SQL1, SQL2);
         em.getTransaction().commit();
     }
@@ -422,10 +423,18 @@ public class TestPessimisticLocks extend
         // Only run this test on DB2 and Derby for now.  It could cause
         // the test to hang on other platforms.
         if (!(dict instanceof DerbyDictionary ||
-              dict instanceof DB2Dictionary)) {
+              dict instanceof DB2Dictionary ||
+              dict instanceof InformixDictionary)) {
             return;
         }
         
+        // Informix currently requires the lock timeout to be set directly on the dictionary
+        if (dict instanceof InformixDictionary) {
+            InformixDictionary ifxDict = (InformixDictionary)((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance();
+            ifxDict.lockModeEnabled = true;
+            ifxDict.lockWaitSeconds = 5;
+        }
+
         EntityManager em = emf.createEntityManager();
         
         resetSQL();
@@ -459,8 +468,11 @@ public class TestPessimisticLocks extend
             Map<String,Object> props = new HashMap<String,Object>();
             // This property does not have any effect on Derby for the locking
             // condition produced by this test.  Instead, Derby uses the 
-            // lock timeout value specified in the config (pom.xml)
-            props.put("javax.persistence.lock.timeout", 5000);
+            // lock timeout value specified in the config (pom.xml).  On Informix,
+            // the dictionary level timeout (set above) will be used.
+            if (!(dict instanceof InformixDictionary)) {
+                props.put("javax.persistence.lock.timeout", 5000);
+            }
             em.getTransaction().begin();
             getLog().trace("Main: refresh with force increment");
             em.refresh(ve, LockModeType.PESSIMISTIC_FORCE_INCREMENT, props);