You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2007/09/11 07:32:38 UTC

svn commit: r574464 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/

Author: fancy
Date: Mon Sep 10 22:32:37 2007
New Revision: 574464

URL: http://svn.apache.org/viewvc?rev=574464&view=rev
Log:
OPENJPA-360 SQL FOR UPDATE OF incorrectly generated for DB2 UDB version8.1 or earlier and DB2 ISeries V5R3 or earlier.
These  DB2 version also require the "optimize for <n> row" clause appear before FOR UPDATE clause.
Due to this requirement, the OPTIMIZE clause will  appear before FOR UPDATE clause for all DB2 versions.
Also fixed the affected testcases.

Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestIsolationLevelOverride.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestOptimizeForClause.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestSelectForUpdateOverride.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?rev=574464&r1=574463&r2=574464&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java Mon Sep 10 22:32:37 2007
@@ -50,12 +50,12 @@
     public String optimizeClause = "optimize for";
     public String rowClause = "row";
     protected int db2ServerType = 0;
-    protected static final int db2ISeriesV5R3OrEarlier = 1;
-    protected static final int db2UDBV81OrEarlier = 2;
-    protected static final int db2ZOSV8xOrLater = 3;
-    protected static final int db2UDBV82OrLater = 4;
-    protected static final int db2ISeriesV5R4OrLater = 5;
-	private static final String forUpdateOfClause = "FOR UPDATE OF";
+    public static final int db2ISeriesV5R3OrEarlier = 1;
+    public static final int db2UDBV81OrEarlier = 2;
+    public static final int db2ZOSV8xOrLater = 3;
+    public static final int db2UDBV82OrLater = 4;
+    public static final int db2ISeriesV5R4OrLater = 5;
+	private static final String forUpdate = "FOR UPDATE";
     private static final String withRSClause = "WITH RS";
     private static final String withRRClause = "WITH RR";
     private static final String useKeepUpdateLockClause
@@ -313,9 +313,12 @@
      * updateClause and isolationLevel hints
      */
     protected String getForUpdateClause(JDBCFetchConfiguration fetch,
-        boolean forUpdate) {
+        boolean isForUpdate) {
         int isolationLevel;
-        StringBuffer forUpdateString = new StringBuffer();
+        // For db2UDBV81OrEarlier and db2ISeriesV5R3OrEarlier:
+        // "optimize for" clause appears before "for update" clause.
+        StringBuffer forUpdateString = new StringBuffer(
+            getOptimizeClause(fetch));
         try {
             // Determine the isolationLevel; the fetch
             // configuration data overrides the persistence.xml value
@@ -324,16 +327,15 @@
             else
                 isolationLevel = conf.getTransactionIsolationConstant();
 
-            if (forUpdate) {
+            if (isForUpdate) {
                 switch(db2ServerType) {
                 case db2ISeriesV5R3OrEarlier:
                 case db2UDBV81OrEarlier:
-                    if (isolationLevel ==
-                        Connection.TRANSACTION_READ_UNCOMMITTED) {
-                        forUpdateString.append(" ").append(withRSClause)
-                            .append(" ").append(forUpdateOfClause);
-                    } else
-                        forUpdateString.append(" ").append(forUpdateOfClause);
+                    if (isolationLevel == Connection.TRANSACTION_SERIALIZABLE)
+                        forUpdateString.append(" ").append(forUpdateClause);
+                    else 
+                        forUpdateString.append(" ").append(forUpdate)
+                            .append(" ").append(withRSClause);
                     break;
                 case db2ZOSV8xOrLater:
                 case db2UDBV82OrLater:
@@ -368,7 +370,7 @@
         return forUpdateString.toString();
     }
 
-    public boolean isDB2UDBV82OrLater() throws SQLException {
+    public boolean isDB2UDBV82OrLater() {
         boolean match = false;
         if ((databaseProductVersion.indexOf("SQL") != -1
             || databaseProductName.indexOf("DB2/") != -1)
@@ -377,8 +379,7 @@
         return match;
     }
 
-    public boolean isDB2ZOSV8xOrLater()
-       throws SQLException {
+    public boolean isDB2ZOSV8xOrLater() {
        boolean match = false;
        if ((databaseProductVersion.indexOf("DSN") != -1
            || databaseProductName.indexOf("DB2/") == -1)
@@ -387,8 +388,7 @@
         return match;
     }
 
-    public boolean isDB2ISeriesV5R3OrEarlier()
-       throws SQLException {
+    public boolean isDB2ISeriesV5R3OrEarlier() {
        boolean match = false;
        if (databaseProductName.indexOf("AS") != -1
            && ((maj == 5 && min <=3) || maj < 5))
@@ -396,8 +396,7 @@
        return match;
     }
 
-    public boolean isDB2ISeriesV5R4OrLater()
-       throws SQLException {
+    public boolean isDB2ISeriesV5R4OrLater() {
        boolean match = false;
        if (databaseProductName.indexOf("AS") != -1
            && (maj >=6 || (maj == 5 && min >=4)))
@@ -405,7 +404,7 @@
       return match;
     }
 
-    public boolean isDB2UDBV81OrEarlier() throws SQLException {
+    public boolean isDB2UDBV81OrEarlier() {
         boolean match = false;
         if ((databaseProductVersion.indexOf("SQL") != -1 
            || databaseProductName.indexOf("DB2/") != -1) &&
@@ -465,17 +464,16 @@
         }
     }
 
-    public SQLBuffer toSelect(Select sel, boolean forUpdate,
-        JDBCFetchConfiguration fetch) {
-        SQLBuffer buf = super.toSelect(sel, forUpdate, fetch);
-
-        if (sel.getExpectedResultCount() > 0) {
+    protected String getOptimizeClause(JDBCFetchConfiguration fetch) {
+        if (sel != null && sel.getExpectedResultCount() > 0) {
+            StringBuffer buf = new StringBuffer();
             buf.append(" ").append(optimizeClause).append(" ")
                 .append(String.valueOf(sel.getExpectedResultCount()))
                 .append(" ").append(rowClause);
+            return buf.toString();
         }
 
-        return buf;
+        return "";
     }
 
     public OpenJPAException newStoreException(String msg, SQLException[] causes,

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=574464&r1=574463&r2=574464&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 Mon Sep 10 22:32:37 2007
@@ -325,6 +325,7 @@
     private Method _setBytes = null;
     private Method _setString = null;
     private Method _setCharStream = null;
+    protected transient Select sel = null;
 
     public DBDictionary() {
         fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
@@ -1988,6 +1989,7 @@
      */
     public SQLBuffer toSelect(Select sel, boolean forUpdate,
         JDBCFetchConfiguration fetch) {
+        this.sel = sel;
         sel.addJoinClassConditions();
         boolean update = forUpdate && sel.getFromSelect() == null;
         SQLBuffer select = getSelects(sel, false, update);
@@ -2198,11 +2200,11 @@
      * updateClause and isolationLevel hints
      */
     protected String getForUpdateClause(JDBCFetchConfiguration fetch,
-        boolean forUpdate) {
+        boolean isForUpdate) {
         if (fetch != null && fetch.getIsolation() != -1) {
             throw new InvalidStateException(_loc.get(
                 "isolation-level-config-not-supported", getClass().getName()));
-        } else if (forUpdate && !simulateLocking) {
+        } else if (isForUpdate && !simulateLocking) {
             assertSupport(supportsSelectForUpdate, "SupportsSelectForUpdate");
             return forUpdateClause;
         } else {

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestIsolationLevelOverride.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestIsolationLevelOverride.java?rev=574464&r1=574463&r2=574464&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestIsolationLevelOverride.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestIsolationLevelOverride.java Mon Sep 10 22:32:37 2007
@@ -81,37 +81,23 @@
 
                 q.getResultList();
                 if (dict instanceof DB2Dictionary) {
-                    if ((((DB2Dictionary) dict).getDb2ServerType() == 1)
-                        || (((DB2Dictionary) dict).getDb2ServerType()== 2)) {
+                    int db2server = ((DB2Dictionary) dict).getDb2ServerType();
+                    if (db2server == DB2Dictionary.db2ISeriesV5R3OrEarlier
+                        || db2server == DB2Dictionary.db2UDBV81OrEarlier) {
                         assertEquals(1, sql.size());
-                        assertSQL("SELECT t0.id, t0.booleanField, t0.byteField,"
-                            + " t0.charField, t0.dateField, t0.doubleField,"
-                            + " t0.floatField, t0.intField, t0.longField, "
-                            + "t0.shortField, t0.stringField FROM "
-                            + "AllFieldTypes t0 WHERE \\(t0.intField = \\?\\) "
-                            + " FOR UPDATE OF");
+                        assertContainsSQL(" FOR UPDATE");
                     }
                     // it is DB2 v82 or later
-                    else if ((((DB2Dictionary) dict).getDb2ServerType() == 3)
-                        || (((DB2Dictionary) dict).getDb2ServerType() == 4)) {
+                    else if (db2server == DB2Dictionary.db2ZOSV8xOrLater
+                        || db2server == DB2Dictionary.db2UDBV82OrLater) {
                         assertEquals(1, sql.size());
-                        assertSQL("SELECT t0.id, t0.booleanField, t0.byteField,"
-                            + " t0.charField, t0.dateField, t0.doubleField,"
-                            + " t0.floatField, t0.intField, t0.longField, "
-                            + "t0.shortField, t0.stringField FROM "
-                            + "AllFieldTypes t0 WHERE \\(t0.intField = \\?\\) "
-                            + " FOR READ ONLY WITH RR USE AND KEEP " 
+                        assertContainsSQL(" FOR READ ONLY WITH RR USE AND KEEP " 
                             + "UPDATE LOCKS");
                     }
-                    else if (((DB2Dictionary) dict).getDb2ServerType() == 5) {
+                    else if (db2server == DB2Dictionary.db2ISeriesV5R4OrLater) {
                         assertEquals(1, sql.size());
-                        assertSQL("SELECT t0.id, t0.booleanField, t0.byteField,"
-                            + " t0.charField, t0.dateField, t0.doubleField,"
-                            + " t0.floatField, t0.intField, t0.longField, "
-                            + "t0.shortField, t0.stringField FROM "
-                            + "AllFieldTypes t0 WHERE \\(t0.intField = \\?\\) "
-                            + " FOR READ ONLY WITH RR USE AND KEEP EXCLUSIVE " 
-                            + "LOCKS");
+                        assertContainsSQL(" FOR READ ONLY WITH RR USE AND KEEP" 
+                            + " EXCLUSIVE LOCKS");
                     }    
                     else {
                         fail("OpenJPA currently only supports " 
@@ -124,37 +110,25 @@
                     .setIsolation(IsolationLevel.SERIALIZABLE);
                 em.find(AllFieldTypes.class, 0);
                 if (dict instanceof DB2Dictionary ) {
-                    if ((((DB2Dictionary) dict).getDb2ServerType() == 1)
-                        || (((DB2Dictionary) dict).getDb2ServerType()== 2)) {
+                    int db2server = ((DB2Dictionary) dict).getDb2ServerType();
+                    if (db2server == DB2Dictionary.db2ISeriesV5R3OrEarlier
+                        || db2server == DB2Dictionary.db2UDBV81OrEarlier) {
                         assertEquals(1, sql.size());
-                        assertSQL("SELECT t0.booleanField, t0.byteField, "
-                            + "t0.charField, t0.dateField, t0.doubleField,"
-                            + " t0.floatField, t0.intField, t0.longField,"
-                            + " t0.shortField, t0.stringField FROM "
-                            + "AllFieldTypes t0 WHERE t0.id = \\? "
-                            + " FOR UPDATE OF optimize for 1 row");
+                        assertContainsSQL(" optimize for 1 row FOR UPDATE");
                     }
                     // it is DB2 v82 or later
-                    else if ((((DB2Dictionary) dict).getDb2ServerType() == 3)
-                        || (((DB2Dictionary) dict).getDb2ServerType() == 4)) {
+                    else if (db2server == DB2Dictionary.db2ZOSV8xOrLater
+                        || db2server == DB2Dictionary.db2UDBV82OrLater) {
                         assertEquals(1, sql.size());
-                        assertSQL("SELECT t0.booleanField, t0.byteField, "
-                            + "t0.charField, t0.dateField, t0.doubleField,"
-                            + " t0.floatField, t0.intField, t0.longField,"
-                            + " t0.shortField, t0.stringField FROM "
-                            + "AllFieldTypes t0 WHERE t0.id = \\? "
+                        assertContainsSQL(" optimize for 1 row"
                             + " FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS" 
-                            + " optimize for 1 row");
+                            );
                     }
-                    else if (((DB2Dictionary) dict).getDb2ServerType() == 5) {
+                    else if (db2server == DB2Dictionary.db2ISeriesV5R4OrLater) {
                         assertEquals(1, sql.size());
-                        assertSQL("SELECT t0.booleanField, t0.byteField, "
-                            + "t0.charField, t0.dateField, t0.doubleField,"
-                            + " t0.floatField, t0.intField, t0.longField,"
-                            + " t0.shortField, t0.stringField FROM "
-                            + "AllFieldTypes t0 WHERE t0.id = \\? "
+                        assertContainsSQL(" optimize for 1 row"
                             + " FOR READ ONLY WITH RR USE AND KEEP EXCLUSIVE" 
-                            + " LOCKS optimize for 1 row");
+                            + " LOCKS");
                     }    
                     else {
                         fail("OpenJPA currently only supports per-query" 

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestOptimizeForClause.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestOptimizeForClause.java?rev=574464&r1=574463&r2=574464&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestOptimizeForClause.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestOptimizeForClause.java Mon Sep 10 22:32:37 2007
@@ -81,22 +81,14 @@
                }     
                if (dict instanceof DB2Dictionary) {
                    assertEquals(1, sql.size());
-                   assertSQL("SELECT t0.id, t0.booleanField, t0.byteField," +
-                       " t0.charField, t0.dateField, t0.doubleField, " +
-                       "t0.floatField, t0.intField, t0.longField, " +
-                       "t0.shortField, t0.stringField FROM AllFieldTypes " +
-                       "t0 WHERE \\(t0.intField = \\?\\)  optimize for 8 row");
+                   assertContainsSQL(" optimize for 8 row");
                }
             }
             else {
                  em.find(AllFieldTypes.class, 0);
                  if (dict instanceof DB2Dictionary ) {
                     assertEquals(1, sql.size());
-                    assertSQL("SELECT t0.booleanField, t0.byteField, " +
-                        "t0.charField, t0.dateField, t0.doubleField, " +
-                        "t0.floatField, t0.intField, t0.longField, " +
-                        "t0.shortField, t0.stringField FROM AllFieldTypes" +
-                        " t0 WHERE t0.id = \\?  optimize for 1 row");
+                    assertContainsSQL(" optimize for 1 row");
                 }
                    
             }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestSelectForUpdateOverride.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestSelectForUpdateOverride.java?rev=574464&r1=574463&r2=574464&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestSelectForUpdateOverride.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestSelectForUpdateOverride.java Mon Sep 10 22:32:37 2007
@@ -33,7 +33,14 @@
     extends SQLListenerTestCase {
 
     public void setUp() {
-        setUp(AllFieldTypes.class,
+        setUp(
+//                "openjpa.ConnectionDriverName", 
+//                "org.apache.commons.dbcp.BasicDataSource",
+                
+                "openjpa.ConnectionProperties",
+                "DriverClassName=com.ibm.db2.jcc.DB2Driver,Url=jdbc:db2:demodb"
+                ,"openjpa.jdbc.SynchronizeMappings",
+                AllFieldTypes.class,
             "openjpa.Optimistic", "false",
             "openjpa.LockManager", "pessimistic",
             "openjpa.ReadLockLevel", "none");
@@ -57,37 +64,24 @@
             em.find(AllFieldTypes.class, 0);
             assertEquals(1, sql.size());
             if (dict instanceof DB2Dictionary) {
-                if ((((DB2Dictionary) dict).getDb2ServerType() == 1)
-                    || (((DB2Dictionary) dict).getDb2ServerType()== 2)) {
+                int db2server = ((DB2Dictionary) dict).getDb2ServerType();
+                if (db2server == DB2Dictionary.db2ISeriesV5R3OrEarlier
+                    || db2server == DB2Dictionary.db2UDBV81OrEarlier) {
                     assertEquals(1, sql.size());
-                    assertSQL("SELECT t0.booleanField, t0.byteField, "
-                        + "t0.charField, t0.dateField, t0.doubleField,"
-                        + " t0.floatField, t0.intField, t0.longField,"
-                        + " t0.shortField, t0.stringField FROM "
-                        + "AllFieldTypes t0 WHERE t0.id = \\? "
-                        + " FOR UPDATE OF optimize for 1 row");
+                    assertContainsSQL(" optimize for 1 row FOR UPDATE");
                 }
                 // it is DB2 v82 or later
-                else if ((((DB2Dictionary) dict).getDb2ServerType() == 3)
-                    || (((DB2Dictionary) dict).getDb2ServerType() == 4)) {
+                else if (db2server == DB2Dictionary.db2ZOSV8xOrLater
+                    || db2server == DB2Dictionary.db2UDBV82OrLater) {
                     assertEquals(1, sql.size());
-                    assertSQL("SELECT t0.booleanField, t0.byteField, "
-                        + "t0.charField, t0.dateField, t0.doubleField,"
-                        + " t0.floatField, t0.intField, t0.longField,"
-                        + " t0.shortField, t0.stringField FROM "
-                        + "AllFieldTypes t0 WHERE t0.id = \\? "
-                        + " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS" 
-                        + " optimize for 1 row");
+                    assertContainsSQL(" optimize for 1 row"
+                        + " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS");
                 }
-                else if (((DB2Dictionary) dict).getDb2ServerType() == 5) {
+                else if (db2server == DB2Dictionary.db2ISeriesV5R4OrLater) {
                     assertEquals(1, sql.size());
-                    assertSQL("SELECT t0.booleanField, t0.byteField, "
-                        + "t0.charField, t0.dateField, t0.doubleField,"
-                        + " t0.floatField, t0.intField, t0.longField,"
-                        + " t0.shortField, t0.stringField FROM "
-                        + "AllFieldTypes t0 WHERE t0.id = \\? "
+                    assertContainsSQL(" optimize for 1 row"
                         + " FOR READ ONLY WITH RS USE AND KEEP EXCLUSIVE LOCKS"
-                        + " optimize for 1 row");
+                        );
                 }    
                 else {
                     fail("OpenJPA currently only supports per-query isolation " 

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=574464&r1=574463&r2=574464&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 Mon Sep 10 22:32:37 2007
@@ -78,6 +78,21 @@
                 + " should not have been executed in SQL statements: " + sql);
     }
 
+    /**
+     * Confirm that the executed SQL String contains the specified sqlExp.
+     *
+     * @param sqlExp the SQL expression. E.g., "SELECT BADCOLUMN .*"
+     */
+    public void assertContainsSQL(String sqlExp) {
+        for (String statement : sql) {
+            if (statement.contains(sqlExp))
+                return;
+        }
+
+        fail("Expected regular expression <" + sqlExp + "> to be"
+            + " contained in SQL statements: " + sql);
+    }
+
     public class Listener
         extends AbstractJDBCListener {