openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jrba...@apache.org
Subject svn commit: r770297 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/ openjpa-persistence-jdbc/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistenc...
Date Thu, 30 Apr 2009 15:50:54 GMT
Author: jrbauer
Date: Thu Apr 30 15:50:53 2009
New Revision: 770297

URL: http://svn.apache.org/viewvc?rev=770297&view=rev
Log:
OPENJPA-964 Committing contributions provided by Donald Woods

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/InformixDictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java
    openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/sql-error-state-codes.xml
    openjpa/trunk/openjpa-persistence-jdbc/pom.xml
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.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=770297&r1=770296&r2=770297&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 Thu Apr 30 15:50:53 2009
@@ -55,6 +55,7 @@
     private static final Localizer _loc = Localizer.forPackage
         (DB2Dictionary.class);
 
+    public static final String VENDOR_IBM = "ibm";
     public String optimizeClause = "optimize for";
     public String rowClause = "row";
     protected int db2ServerType = 0;
@@ -246,6 +247,12 @@
     	super.connectedConfiguration(conn);
 
     	DatabaseMetaData metaData = conn.getMetaData();
+        String driverName = metaData.getDriverName();
+        if (driverName != null && driverName.startsWith("IBM DB2"))
+            driverVendor = VENDOR_IBM;
+        else
+            driverVendor = VENDOR_OTHER;
+
         databaseProductName = nullSafe(metaData.getDatabaseProductName());
         databaseProductVersion = nullSafe(metaData.getDatabaseProductVersion());
         
@@ -849,11 +856,9 @@
             if (subtype == StoreException.LOCK && errorState.equals("57033")
                 && ex.getMessage().indexOf("80") != -1) {
                 recoverable = Boolean.TRUE;
-            } else if (subtype == StoreException.QUERY &&
-                    errorState.equals("57014") &&
-                    ex.getMessage().indexOf("40001") == -1) {
-                // FIXME drwoods - OPENJPA-964 - Need to determine expected DB2
-                // behavior for query timeouts
+            } else if ((subtype == StoreException.QUERY &&
+                errorState.equals("57014")) &&
+                (ex.getErrorCode() == -952 || ex.getErrorCode() == -905)) {
                 recoverable = Boolean.TRUE;
             }
         }

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=770297&r1=770296&r2=770297&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 Thu Apr 30 15:50:53 2009
@@ -27,6 +27,7 @@
 import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Set;
 
 import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
 import org.apache.openjpa.jdbc.schema.Column;
@@ -36,6 +37,7 @@
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.lib.util.ReferenceHashSet;
+import org.apache.openjpa.util.StoreException;
 import org.apache.openjpa.util.UnsupportedException;
 
 /**
@@ -52,6 +54,8 @@
 public class InformixDictionary
     extends DBDictionary {
 
+    public static final String VENDOR_IBM = "ibm";
+
     /**
      * If true, then we will issue a "SET LOCK MODE TO WAIT N"
      * statement whenever we create a {@link Connection}, in order
@@ -121,7 +125,6 @@
             "INT8",
         }));
 
-        supportsQueryTimeout = false;
         supportsLockingWithDistinctClause = false;
         supportsLockingWithMultipleTables = false;
         supportsLockingWithOrderClause = false;
@@ -154,23 +157,25 @@
     public void connectedConfiguration(Connection conn)
         throws SQLException {
         super.connectedConfiguration(conn);
-        if (driverVendor == null) {
-            DatabaseMetaData meta = conn.getMetaData();
-            String driverName = meta.getDriverName();
-            if ("Informix".equalsIgnoreCase(driverName))
-                driverVendor = VENDOR_DATADIRECT;
-            else
-                driverVendor = VENDOR_OTHER;
-            
+
+        DatabaseMetaData meta = conn.getMetaData();
+        String driverName = meta.getDriverName();
+        if (driverName != null) {
             if (driverName.equals("IBM DB2 JDBC Universal Driver Architecture"))
             { 
+                driverVendor = VENDOR_IBM;
                 useJCC = true;
                 try {
                     if (meta.storesLowerCaseIdentifiers()) 
                         schemaCase = SCHEMA_CASE_LOWER;
                 } catch (SQLException e) {}
-            }
-        }
+            } else if ("Informix".equalsIgnoreCase(driverName))
+                driverVendor = VENDOR_DATADIRECT;
+            else
+                driverVendor = VENDOR_OTHER;
+        } else
+            driverVendor = VENDOR_OTHER;
+
         if (isJDBC3) {
             conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
             if (log.isTraceEnabled())
@@ -324,5 +329,23 @@
         return schemaCase;
     }
         
-    
+    @Override
+    protected Boolean matchErrorState(int subtype, Set<String> errorStates,
+        SQLException ex) {
+        Boolean recoverable = null;
+        String errorState = ex.getSQLState();
+        if (errorStates.contains(errorState)) {
+            // 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) {
+                recoverable = Boolean.TRUE;
+            } else if (subtype == StoreException.QUERY &&
+                ex.getErrorCode() == -213) {
+                recoverable = Boolean.TRUE;
+            }
+        }
+        return recoverable;
+    }
 }
\ No newline at end of file

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java?rev=770297&r1=770296&r2=770297&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java Thu Apr 30 15:50:53 2009
@@ -37,6 +37,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
 import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
@@ -1135,4 +1136,26 @@
         }
         return updateSuccessCnt;
     }
+    
+    @Override
+    protected Boolean matchErrorState(int subtype, Set<String> errorStates,
+        SQLException ex) {
+        Boolean recoverable = null;
+        String errorState = ex.getSQLState();
+        int errorCode = ex.getErrorCode();
+        if (errorStates.contains(errorState)) {
+            recoverable = Boolean.FALSE;
+            if ((subtype == StoreException.LOCK)
+                && ((errorState.equals("61000") && (errorCode == 54 ||
+                     errorCode == 60 || errorCode == 4020 ||
+                     errorCode == 4021 || errorCode == 4022))
+                    || (errorState.equals("42000") && errorCode == 2049))) {
+                recoverable = Boolean.TRUE;
+            } else if (subtype == StoreException.QUERY &&
+                errorState.equals("72000") && errorCode == 1013) {
+                recoverable = Boolean.TRUE;
+            }
+        }
+        return recoverable;
+    }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java?rev=770297&r1=770296&r2=770297&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java Thu Apr 30 15:50:53 2009
@@ -1,20 +1,18 @@
 /*
- * 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
- *
+ * 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.    
+ * 
+ * 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.jdbc.sql;
 
@@ -22,25 +20,26 @@
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.sql.Types;
+import java.util.Set;
 
 import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
 import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.util.StoreException;
 
 /**
  * Dictionary for MS SQLServer.
  */
-public class SQLServerDictionary
-    extends AbstractSQLServerDictionary {
+public class SQLServerDictionary extends AbstractSQLServerDictionary {
 
     public static final String VENDOR_MICROSOFT = "microsoft";
     public static final String VENDOR_NETDIRECT = "netdirect";
     public static final String VENDOR_JTDS = "jtds";
 
-    private static final Localizer _loc = Localizer.forPackage
-        (SQLServerDictionary.class);
+    private static final Localizer _loc =
+        Localizer.forPackage(SQLServerDictionary.class);
 
     private String schemaCase = SCHEMA_CASE_PRESERVE;
     /**
@@ -50,19 +49,15 @@
 
     public SQLServerDictionary() {
         platform = "Microsoft SQL Server";
-
         // SQLServer locks on a table-by-table basis
         forUpdateClause = null;
         tableForUpdateClause = "WITH (UPDLOCK)";
-
         supportsNullTableForGetColumns = false;
         requiresAliasForSubselect = true;
-
         stringLengthFunction = "LEN({0})";
     }
 
-    public void connectedConfiguration(Connection conn)
-        throws SQLException {
+    public void connectedConfiguration(Connection conn) throws SQLException {
         super.connectedConfiguration(conn);
         boolean requiresWarnings = true;
         DatabaseMetaData meta = conn.getMetaData();
@@ -72,7 +67,7 @@
             if (driverName != null) {
                 if (driverName.startsWith("Microsoft SQL Server")) {
                     // v1.1, 1.2 or 2.0 driver
-                    driverVendor = VENDOR_MICROSOFT;                
+                    driverVendor = VENDOR_MICROSOFT;
                     // serverMajorVersion of 8==2000, 9==2005, 10==2008
                     if (meta.getDatabaseMajorVersion() >= 9)
                         supportsXMLColumn = true;
@@ -80,7 +75,7 @@
                         // see http://blogs.msdn.com/jdbcteam/archive/2007/05/\
                         // 02/what-is-adaptive-response-buffering-and-why-\
                         // should-i-use-it.aspx
-                        // 2.0 driver connectURL automatically includes 
+                        // 2.0 driver connectURL automatically includes
                         // responseBuffering=adaptive
                         // and disableStatementPooling=true
                         requiresWarnings = false;
@@ -94,16 +89,16 @@
                         if (url != null &&
                             url.startsWith("jdbc:microsoft:sqlserver:"))
                             driverVendor = VENDOR_MICROSOFT;
-                        else if (url != null
-                            && url.startsWith("jdbc:datadirect:sqlserver:"))
+                        else if (url != null &&
+                            url.startsWith("jdbc:datadirect:sqlserver:"))
                             driverVendor = VENDOR_DATADIRECT;
                         else
                             driverVendor = VENDOR_OTHER;
                     }
                     // old way of determining xml support
                     if (driverName.indexOf(platform) != -1) {
-                        String versionString = driverName.
-                            substring(platform.length() + 1);
+                        String versionString =
+                            driverName.substring(platform.length() + 1);
                         if (versionString.indexOf(" ") != -1)
                             versionString = versionString.substring(0,
                                 versionString.indexOf(" "));
@@ -119,18 +114,19 @@
 
         // warn about not using cursors for pre-2.0 MS driver
         // as connectURL includes selectMethod=direct
-        if (((VENDOR_MICROSOFT.equalsIgnoreCase(driverVendor)
-            && requiresWarnings) 
-            || VENDOR_DATADIRECT.equalsIgnoreCase(driverVendor))
-            && (url.toLowerCase().indexOf("selectmethod=cursor") == -1))
+        if (((VENDOR_MICROSOFT.equalsIgnoreCase(driverVendor) &&
+            requiresWarnings) || 
+            VENDOR_DATADIRECT.equalsIgnoreCase(driverVendor)) &&
+            (url.toLowerCase().indexOf("selectmethod=cursor") == -1))
             log.warn(_loc.get("sqlserver-cursor", url));
 
         // warn about prepared statement caching if using pre-2.0 MS drivers
         // as connectURL includes responseBuffering=full
         String props = conf.getConnectionFactoryProperties();
-        if ((props != null) && 
-            VENDOR_MICROSOFT.equalsIgnoreCase(driverVendor) && requiresWarnings
-            && (props.toLowerCase().indexOf("maxcachedstatements=0") == -1))
+        if ((props != null) &&
+            VENDOR_MICROSOFT.equalsIgnoreCase(driverVendor) &&
+            requiresWarnings &&
+            (props.toLowerCase().indexOf("maxcachedstatements=0") == -1))
             log.warn(_loc.get("sqlserver-cachedstmnts"));
     }
 
@@ -147,7 +143,6 @@
                 continue;
 
             typeName = typeName.toUpperCase();
-
             if ("NVARCHAR".equals(typeName))
                 cols[i].setType(Types.VARCHAR);
             else if ("UNIQUEIDENTIFIER".equals(typeName)) {
@@ -162,16 +157,16 @@
         }
         return cols;
     }
-    
+
     protected void appendLength(SQLBuffer buf, int type) {
         if (type == Types.VARCHAR)
-            buf.append("(").append(Integer.toString(characterColumnSize)).
-                    append(")");
+            buf.append("(").append(Integer.toString(characterColumnSize))
+                .append(")");
     }
 
     /**
-     * If this dictionary supports XML type,
-     * use this method to append xml predicate.
+     * If this dictionary supports XML type, use this method to append xml
+     * predicate.
      * 
      * @param buf the SQL buffer to write the comparison
      * @param op the comparison operation to perform
@@ -187,12 +182,13 @@
             appendXmlComparison2(buf, op, lhs, rhs);
         else if (lhsxml)
             appendXmlComparison1(buf, op, lhs, rhs);
-        else 
+        else
             appendXmlComparison1(buf, op, rhs, lhs);
     }
+
     /**
      * Append an xml comparison predicate
-     *
+     * 
      * @param buf the SQL buffer to write the comparison
      * @param op the comparison operation to perform
      * @param lhs the left hand side of the comparison (maps to xml column)
@@ -211,56 +207,67 @@
         else {
             buf.append("sql:column(\"");
             rhs.appendTo(buf);
-            buf.append("\")").
-                append("]') = 1");
+            buf.append("\")").append("]') = 1");
         }
     }
-    
+
     private void appendXmlExist(SQLBuffer buf, FilterValue lhs) {
-        buf.append(lhs.getColumnAlias(
-            lhs.getFieldMapping().getColumns()[0])).
-            append(".exist('").
-            append("/*[");
-        lhs.appendTo(buf);    
+        buf.append(lhs.getColumnAlias(lhs.getFieldMapping().getColumns()[0]))
+            .append(".exist('").append("/*[");
+        lhs.appendTo(buf);
     }
-    
+
     /**
      * Append an xml comparison predicate (both operands map to xml column)
-     *
+     * 
      * @param buf the SQL buffer to write the comparison
      * @param op the comparison operation to perform
      * @param lhs the left hand side of the comparison (maps to xml column)
      * @param rhs the right hand side of the comparison (maps to xml column)
      */
-    private void appendXmlComparison2(SQLBuffer buf, String op, 
+    private void appendXmlComparison2(SQLBuffer buf, String op,
         FilterValue lhs, FilterValue rhs) {
         appendXmlValue(buf, lhs);
         buf.append(" ").append(op).append(" ");
         appendXmlValue(buf, rhs);
     }
-    
+
     private void appendXmlValue(SQLBuffer buf, FilterValue val) {
         Class rc = Filters.wrap(val.getType());
         int type = getJDBCType(JavaTypes.getTypeCode(rc), false);
-        boolean isXmlAttribute = (val.getXmlMapping() == null) ? false
-                : val.getXmlMapping().isXmlAttribute();
-        buf.append(val.getColumnAlias(
-            val.getFieldMapping().getColumns()[0])).
-            append(".value(").
-            append("'(/*/");
+        boolean isXmlAttribute = (val.getXmlMapping() == null)
+            ? false : val.getXmlMapping().isXmlAttribute();
+        buf.append(val.getColumnAlias(val.getFieldMapping().getColumns()[0]))
+            .append(".value(").append("'(/*/");
         val.appendTo(buf);
         if (!isXmlAttribute)
             buf.append("/text()");
-        buf.append(")[1]','").
-            append(getTypeName(type));
+        buf.append(")[1]','").append(getTypeName(type));
         appendLength(buf, type);
         buf.append("')");
     }
-    
+
     /**
      * Return DB specific schemaCase
      */
     public String getSchemaCase() {
         return schemaCase;
     }
+
+    @Override
+    protected Boolean matchErrorState(int subtype, Set<String> errorStates,
+        SQLException ex) {
+        Boolean recoverable = null;
+        String errorState = ex.getSQLState();
+        if (errorStates.contains(errorState)) {
+            recoverable = Boolean.FALSE;
+            if (subtype == StoreException.LOCK && errorState.equals("1222")) {
+                recoverable = Boolean.TRUE;
+            } else if (subtype == StoreException.QUERY &&
+                errorState.equals("HY008")) {
+                recoverable = Boolean.TRUE;
+            }
+        }
+        return recoverable;
+    }
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/sql-error-state-codes.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/sql-error-state-codes.xml?rev=770297&r1=770296&r2=770297&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/sql-error-state-codes.xml (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/sql-error-state-codes.xml Thu Apr 30 15:50:53 2009
@@ -29,12 +29,12 @@
 <sql-state-codes>
 
 	<dictionary class="org.apache.openjpa.jdbc.sql.DB2Dictionary">
-		<lock>40001,57033</lock>
+		<lock>40001,57033,57011</lock>
 		<referential-integrity>23502,42912,23001,23504,23511,23512,23513,23515,23520</referential-integrity>
 		<object-exists>23505</object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query>57014</query>
+		<query>57014</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.DerbyDictionary">
@@ -43,25 +43,25 @@
 		<object-exists>23505</object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query>XCL52</query>
+		<query>XCL52</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.SQLServerDictionary">
-		<lock>1205</lock>
+		<lock>1204,1205,1222</lock>
 		<referential-integrity>544,2601,2627,8114,8115</referential-integrity>
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic>1205</optimistic>
-        <query></query>
+		<query>HY008</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.SybaseDictionary">
-		<lock>1205</lock>
+		<lock>1204,1205,1279</lock>
 		<referential-integrity>423,511,515,530,547,2601,2615,2714</referential-integrity>
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic>1205</optimistic>
-        <query></query>
+		<query>611</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.AccessDictionary">
@@ -70,16 +70,16 @@
 		<object-exists>23505,456c</object-exists>
 		<object-not-found></object-not-found>
 		<optimistic>40XL1,40001</optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.CacheDictionary">
-		<lock>40001</lock>
+		<lock>40001,40XL1,40XL2</lock>
 		<referential-integrity>22001,22005,23502,23503,23513,X0Y32</referential-integrity>
 		<object-exists>23505,456c</object-exists>
 		<object-not-found></object-not-found>
-		<optimistic>40XL1,40001</optimistic>
-        <query></query>
+		<optimistic></optimistic>
+		<query>XCL52</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.EmpressDictionary">
@@ -88,16 +88,16 @@
 		<object-exists>23505,456c</object-exists>
 		<object-not-found></object-not-found>
 		<optimistic>40XL1,40001</optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.FoxProDictionary">
-		<lock>40001</lock>
+		<lock>1222,1599,40001</lock>
 		<referential-integrity>22001,22005,23502,23503,23513,X0Y32</referential-integrity>
 		<object-exists>23505,456c</object-exists>
 		<object-not-found></object-not-found>
 		<optimistic>40XL1,40001</optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.H2Dictionary">
@@ -106,7 +106,7 @@
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.HSQLDictionary">
@@ -115,16 +115,16 @@
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.InformixDictionary">
-		<lock></lock>
+		<lock>-143,-154</lock>
 		<referential-integrity>-239,-268,-692,-11030</referential-integrity>
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query>IX000</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.InterbaseDictionary">
@@ -133,7 +133,7 @@
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.FirebirdDictionary">
@@ -142,7 +142,7 @@
 		<object-exists>335544665</object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.JDataStoreDictionary">
@@ -151,25 +151,25 @@
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.MySQLDictionary">
-		<lock>1213</lock>
+		<lock>1205,1213</lock>
 		<referential-integrity>630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557</referential-integrity>
 		<object-exists>23000</object-exists>
 		<object-not-found></object-not-found>
-		<optimistic>41000,1205,1213</optimistic>
-        <query></query>
+		<optimistic>41000</optimistic>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.OracleDictionary">
-		<lock></lock>
+		<lock>42000,61000</lock>
 		<referential-integrity>1,1400,1722,2291,2292</referential-integrity>
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query>72000</query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.PointbaseDictionary">
@@ -178,7 +178,7 @@
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic></optimistic>
-        <query></query>
+		<query></query>
 	</dictionary>
 	
 	<dictionary class="org.apache.openjpa.jdbc.sql.PostgresDictionary">
@@ -187,7 +187,7 @@
 		<object-exists></object-exists>
 		<object-not-found></object-not-found>
 		<optimistic>55P03</optimistic>
-        <query></query>
+		<query>57014</query>
 	</dictionary>
 	
-</sql-state-codes>
\ No newline at end of file
+</sql-state-codes>

Modified: openjpa/trunk/openjpa-persistence-jdbc/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/pom.xml?rev=770297&r1=770296&r2=770297&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/pom.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/pom.xml Thu Apr 30 15:50:53 2009
@@ -77,11 +77,12 @@
                 <dependency>
                     <groupId>hsqldb</groupId>
                     <artifactId>hsqldb</artifactId>
-                    <version>1.8.0.7</version>
+                    <version>${hsqldb.version}</version>
                     <scope>test</scope>
                 </dependency>
             </dependencies>
-             <properties>
+            <properties>
+                <hsqldb.version>1.8.0.7</hsqldb.version>
                 <connection.driver.name>org.hsqldb.jdbcDriver</connection.driver.name>
                 <connection.url>jdbc:hsqldb:target/database/openjpa-hsqldb-database;create=true</connection.url>
                 <connection.username>sa</connection.username>
@@ -97,11 +98,12 @@
                 <dependency>
                     <groupId>mysql</groupId>
                     <artifactId>mysql-connector-java</artifactId>
-                    <version>5.1.5</version>
+                    <version>${mysql.version}</version>
                     <scope>test</scope>
                 </dependency>
             </dependencies>
             <properties>
+                <mysql.version>5.1.5</mysql.version>
                 <connection.driver.name>com.mysql.jdbc.Driver</connection.driver.name>
                 <connection.url>${openjpa.mysql.url}</connection.url>
                 <connection.username>${openjpa.mysql.username}</connection.username>
@@ -117,11 +119,12 @@
                 <dependency>
                     <groupId>postgresql</groupId>
                     <artifactId>postgresql</artifactId>
-                    <version>8.3-603.jdbc3</version>
+                    <version>${postgresql.version}</version>
                     <scope>test</scope>
                 </dependency>
             </dependencies>
             <properties>
+                <postgresql.version>8.3-603.jdbc3</postgresql.version>
                 <connection.driver.name>org.postgresql.Driver</connection.driver.name>
                 <connection.url>${openjpa.postgresql.url}</connection.url>
                 <connection.username>${openjpa.postgresql.username}</connection.username>
@@ -129,10 +132,72 @@
             </properties>
         </profile>
 
+        <!-- Profile for testing with SQLServer DB using MS JDBC driver -->
+        <profile>
+            <!--
+                Example MS SQL profile. You can use this profile if you:
+                1) have the MS SQL artifacts installed in a local repo and
+                supply the URL:
+                    -Dmssql.maven.repo=http://my.local.repo
+                2) have a copy of the MS SQL JDBC driver from:
+                    http://msdn.microsoft.com/en-us/data/aa937724.aspx
+                and run the following commands :
+                    mvn install:install-file -Dfile=${path to sqljdbc.jar} \
+                                             -DgroupId=com.microsoft.sqlserver \
+                                             -DartifactId=sqljdbc \
+                                             -Dversion=2.0 \
+                                             -Dpackaging=jar
+
+                You must also set the following properties:
+                    -Dopenjpa.mssql.url=jdbc:sqlserver://<HOST>:<PORT>;\
+                    	DataBaseName=<DBNAME>
+                    -Dopenjpa.mssql.username=<mssql_uid>
+                    -Dopenjpa.mssql.password=<mssql_pwd>
+
+                Optionally, you can override the default groupId and version
+                by also supplying the following properties:
+                    -Dmssql.groupid=com.microsoft.sqlserver
+                    -Dmssql.version=2.0
+            -->
+            <id>test-mssql</id>
+            <dependencies>
+                <dependency>
+                    <groupId>${mssql.groupid}</groupId>
+                    <artifactId>${mssql.artifactid}</artifactId>
+                    <version>${mssql.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <properties>
+                <mssql.maven.repo>http://not.real.repository</mssql.maven.repo>
+                <mssql.groupid>com.microsoft.sqlserver</mssql.groupid>
+                <mssql.artifactid>sqljdbc</mssql.artifactid>
+                <mssql.version>2.0</mssql.version>
+                <connection.driver.name>com.microsoft.sqlserver.jdbc.SQLServerDriver</connection.driver.name>
+                <connection.url>${openjpa.mssql.url}</connection.url>
+                <connection.username>${openjpa.mssql.username}</connection.username>
+                <connection.password>${openjpa.mssql.password}</connection.password>
+            </properties>
+            <repositories>
+                <repository>
+                    <id>mssql.repository</id>
+                    <name>MSSQL Repository</name>
+                    <url>${mssql.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 SQLServer DB using the jTDS driver -->
         <profile>
             <id>test-sqlserver</id>
-            <activation><property><name>test-sqlserver</name></property></activation>
             <dependencies>
                 <dependency>
                     <groupId>net.sourceforge.jtds</groupId>
@@ -272,22 +337,25 @@
                     -Dopenjpa.db2.username=<db2_uid>
                     -Dopenjpa.db2.password=<db2_pwd>
 
-                Optionally, you can override the default DB2 groupId and version
-                by also supplying the following properties:
+                Optionally, you can override the default DB2 groupId,
+                artifactIds and version by also supplying the following
+                properties:
                     -Ddb2.groupid=com.ibm.db2
+                    -Dids.driver.artifactid=jcc-driver
+                    -Dids.license.artifactid=jcc-license
                     -Ddb2.version=9.5
             -->
             <id>test-db2-jcc</id>
             <dependencies>
                 <dependency>
                     <groupId>${db2.groupid}</groupId>
-                    <artifactId>jcc-driver</artifactId>
+                    <artifactId>${db2.driver.artifactid}</artifactId>
                     <version>${db2.version}</version>
                     <scope>test</scope>
                 </dependency>
                 <dependency>
                     <groupId>${db2.groupid}</groupId>
-                    <artifactId>jcc-license</artifactId>
+                    <artifactId>${db2.license.artifactid}</artifactId>
                     <version>${db2.version}</version>
                     <scope>test</scope>
                 </dependency>
@@ -295,6 +363,8 @@
             <properties>
                 <db2.maven.repo>http://not.a.real.repository</db2.maven.repo>
                 <db2.groupid>com.ibm.db2</db2.groupid>
+                <db2.driver.artifactid>jcc-driver</db2.driver.artifactid>
+                <db2.license.artifactid>jcc-license</db2.license.artifactid>
                 <db2.version>9.5</db2.version>
                 <connection.driver.name>com.ibm.db2.jcc.DB2Driver</connection.driver.name>
                 <connection.url>${openjpa.db2.url}</connection.url>
@@ -319,6 +389,72 @@
         </profile>          
         <profile>
             <!-- 
+                Example Informix JCC profile. You can use this profile if you:
+                1a) have the DB2 JCC artifacts installed in a local repo and 
+                supply the URL:
+	            -Dids.maven.repo=http://my.local.repo
+                1b) or have a copy of the DB2 JCC driver and run the commands
+                listed above in the test-db2-jcc profile.
+		2) have the DRDA service enabled on the IDS server, which
+                is usually port 9089
+
+                You must also set the following properties:
+                    -Dopenjpa.ids.url=jdbc:ids://<HOST>:<PORT>/<DBNAME>
+                    -Dopenjpa.ids.username=<ids_uid>
+                    -Dopenjpa.ids.password=<ids_pwd>
+
+                Optionally, you can override the default DB2 JCC groupId,
+                artifactIds and version by also supplying the following
+                properties:
+                    -Dids.groupid=com.ibm.db2
+                    -Dids.driver.artifactid=jcc-driver
+                    -Dids.license.artifactid=jcc-license
+                    -Dids.version=9.5
+            -->
+            <id>test-ids-jcc</id>
+            <dependencies>
+                <dependency>
+                    <groupId>${ids.groupid}</groupId>
+                    <artifactId>${ids.driver.artifactid}</artifactId>
+                    <version>${ids.version}</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>${ids.groupid}</groupId>
+                    <artifactId>${ids.license.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.ibm.db2</ids.groupid>
+                <ids.driver.artifactid>jcc-driver</ids.driver.artifactid>
+                <ids.license.artifactid>jcc-license</ids.license.artifactid>
+                <ids.version>9.5</ids.version>
+                <connection.driver.name>com.ibm.db2.jcc.DB2Driver</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>
+            <!-- 
                 Example oracle profile. You can use this profile if you:
                 1) have the Oracle artifacts installed in a local repo and
                 supply the URL:
@@ -345,7 +481,7 @@
             <dependencies>
                 <dependency>
                     <groupId>${oracle.groupid}</groupId>
-                    <artifactId>jdbc-driver</artifactId>
+                    <artifactId>${oracle.artifactid}</artifactId>
                     <version>${oracle.version}</version>
                     <scope>test</scope>
                 </dependency>
@@ -353,6 +489,7 @@
             <properties>
                 <oracle.maven.repo>http://not.a.real.repository</oracle.maven.repo>
                 <oracle.groupid>com.oracle</oracle.groupid>
+                <oracle.artifactid>jdbc-driver</oracle.artifactid>
                 <oracle.version>10g</oracle.version>
                 <connection.driver.name>oracle.jdbc.driver.OracleDriver</connection.driver.name>
                 <connection.url>${openjpa.oracle.url}</connection.url>

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=770297&r1=770296&r2=770297&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 Apr 30 15:50:53 2009
@@ -25,8 +25,12 @@
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+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.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.jdbc.sql.SQLServerDictionary;
 import org.apache.openjpa.kernel.Broker;
 import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.persistence.JPAFacadeHelper;
@@ -37,7 +41,6 @@
 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;
 
 /**
@@ -57,115 +60,85 @@
  * Query operations to validate through cross coverage of items #1-#3:
  *   a) getResultList()
  *   b) getSingleResult()
- *   c) executeUpdate()
+ *   c) executeUpdate() - Requires the db UPDATE trigger
  * Other behaviors to test for:
  *   4) Setting timeout to -1 should be treated as no timeout supplied
  *   5) Setting timeout to < -1 should throw an IllegalArgumentExpection
  *   6) Updates after EM.find()/findAll() are not affected by query timeout
- * Exception generation to test for:
+ * Exception generation to test, covered by 31c and 33c:
  *   If the DB query timeout does not cause a transaction rollback, then a 
- *   QueryTimeoutException should be thrown.
- *     Applicable to:  unknown
+ *      QueryTimeoutException should be thrown.
  *   Else if the DB query timeout causes a transaction rollback, then a 
- *   PersistenceException should be thrown instead of a QTE.
- *     Applicable to:  Derby
+ *      PersistenceException should be thrown instead of a QTE.
  * 
  * @version $Rev$ $Date$
  */
 public class TestQueryTimeout extends SQLListenerTestCase {
 
+    private DBDictionary dict = null;
+    // skip test due to unsupported/untested db
     private boolean skipTests = false;
-
+    // skip some tests due to no DB triggers to cause delay timeout exceptions
+    private boolean skipExceptionTests = false;
+    // skip some tests due to no SELECT query timeouts being generated by the DB
+    private boolean noSelectTimeouts = false;
+    // default native query string to use for update testing 
+    private String nativeUpdateStr = new String("UPDATE QTimeout SET " +
+        "stringField = ? WHERE mod(DELAY(2,id),2)=0");
+    
     @Override
     public void setUp() {
-        super.setUp(DROP_TABLES, QTimeout.class);
+        super.setUp(CLEAR_TABLES, QTimeout.class);
         getLog().trace("setUp()");
-        String[] _strings = new String[] { "a", "b", "c" };
-        QTimeout qt = null;
-        EntityManager em = null;
-
+        dict = ((JDBCConfiguration) emf.getConfiguration())
+            .getDBDictionaryInstance();
+        assertNotNull(dict);
         // 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) {
-            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.");
+            if (dict instanceof DerbyDictionary) {
+                // create some initial entities
+                setupCreateEntities();
+                // create delay function only on Derby, other DBs manual setup
+                setupCreateDBFunction();
+                // create triggers on all DBs
+                // If this fails, skip running the timeout tests on this DB
+                skipExceptionTests = !setupCreateDBTriggers();
+            } else if (dict instanceof DB2Dictionary) {
+                setupCreateEntities();
+                // basic timeout tests fail to pop w/o multiple connections
                 skipTests = true;
+                skipExceptionTests = true;
+            } else if ((dict instanceof SQLServerDictionary) ||
+                (dict instanceof OracleDictionary)) {
+                // create some initial entities
+                setupCreateEntities();
+                // skip running the SELECT timeout tests due to:
+                // C# Delay.dll code on SQLServer
+                // Embedded Java code on Oracle
+                skipTests = true;
+                noSelectTimeouts = true;
+                // create triggers on all DBs
+                skipExceptionTests = !setupCreateDBTriggers();
+                // special case for MS SQL Server and Oracle, as our
+                // Function code doesn't support returning the id for now
+                nativeUpdateStr = "UPDATE QTimeout SET stringField = ? " +
+                    "WHERE id = 1";
+            } else if (dict instanceof InformixDictionary) {
+                // create some initial entities
+                setupCreateEntities();
+                // create triggers on all DBs
+                skipExceptionTests = !setupCreateDBTriggers();
+            } else {
+                // unknown db, so skip all timeout tests
+                skipTests = skipExceptionTests = noSelectTimeouts = true;
+                getLog().info("TestQueryTimeout tests are being skipped, due " +
+                    "to " + dict.platform + " not supporting Query Timeouts.");
             }
         } else {
             getLog().info("TestQueryTimeout tests are being skipped, " +
-                "due to DB not supporting Query Timeouts.");
-            skipTests = true;
-        }
-        if (skipTests)
-            return;
-
-        // create some initial entities
-        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();
-            }
-        }
-
-        // 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 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;
-            }
+                "due to " + dict.platform + " not supporting Query Timeouts.");
+            skipTests = skipExceptionTests = true;
         }
     }
 
@@ -176,6 +149,8 @@
      */
     public void testQueryTimeout1a() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout1a - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout1a() - No Query timeout");
@@ -216,6 +191,8 @@
      */
     public void testQueryTimeout1c() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout1c - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout1c() - No executeUpdate timeout");
@@ -260,6 +237,8 @@
      */
     public void testQueryTimeout21b() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout21b - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout21b() - Map(timeout=0)");
@@ -320,6 +299,8 @@
      */
     public void testQueryTimeout22a() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout22a - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout22a() - QueryHint=0");
@@ -367,6 +348,8 @@
      */
     public void testQueryTimeout23b() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout23b - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         Integer setTime = new Integer(0);
@@ -421,7 +404,9 @@
      * takes 2000+ msecs to complete.
      */
     public void testQueryTimeout31c() {
-        if (skipTests) {
+        if (skipExceptionTests) {
+            getLog().trace("testQueryTimeout31c - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout31c() - PU(timeout=1000), " +
@@ -429,6 +414,7 @@
         OpenJPAEntityManagerFactory emf = null;
         OpenJPAEntityManager em = null;
         Integer setTime = new Integer(1000);
+        boolean bRetry = true;
 
         try {
             // create our EMF with our PU set timeout property
@@ -443,8 +429,7 @@
             // create EM and Query
             em = emf.createEntityManager();
             assertNotNull(em);
-            OpenJPAQuery q = em.createNativeQuery("UPDATE QTimeout SET " +
-                "stringField = ? WHERE mod(DELAY(2,id),2)=0");
+            OpenJPAQuery q = em.createNativeQuery(nativeUpdateStr);
             q.setParameter(1, new String("updated"));
             // verify no default javax.persistence.query.timeout is supplied
             Map<String, Object> hints = q.getHints();
@@ -454,21 +439,34 @@
                 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);
+            em.getTransaction().begin();
+            // if we get a QTE, then retry this once to prove no db rollback
+            for (int i=0; i<=1 && bRetry; i++)
+            {
+                try {
+                    long startTime = System.currentTimeMillis();
+                    @SuppressWarnings("unused")
+                    int count = q.executeUpdate();
+                    // exception should occur before commit
+                    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, MS SQL
+                    // should only retry the statement if db did not rollback
+                    // which should be a QueryTimeoutException
+                    bRetry = checkException("testQueryTimeout31c()", e);
+                    // we're only retrying to prove the right exception type
+                    // was thrown and the transaction wasn't rolled back
+                    if (bRetry)
+                        getLog().trace("testQueryTimeout31c() - retrying... ");
+                }
             }
         } finally {
             if ((em != null) && em.isOpen()) {
@@ -486,7 +484,9 @@
      * Expected Results: QueryTimeoutException or PersistenceException
      */
     public void testQueryTimeout32a() {
-        if (skipTests) {
+        if (skipExceptionTests || noSelectTimeouts) {
+            getLog().trace("testQueryTimeout32a - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout32a() - PU(1000), Map(0), " +
@@ -494,6 +494,7 @@
         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");
@@ -558,12 +559,15 @@
      * Expected Results: QueryTimeoutException or PersistenceException
      */
     public void testQueryTimeout33b() {
-        if (skipTests) {
+        if (skipExceptionTests || noSelectTimeouts) {
+            getLog().trace("testQueryTimeout33b - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         Integer setTime = new Integer(1000);
         getLog().trace("testQueryTimeout33b() - setHint(" + setTime + ")");
         EntityManager em = null;
+
         try {
             em = emf.createEntityManager();
             assertNotNull(em);
@@ -615,7 +619,9 @@
      * Expected Results: QueryTimeoutException (Derby) or PersistenceException
      */
     public void testQueryTimeout33c() {
-        if (skipTests) {
+        if (skipExceptionTests) {
+            getLog().trace("testQueryTimeout33c - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout33c() - PU(timeout=0), setHint(1000)," +
@@ -623,6 +629,7 @@
         OpenJPAEntityManagerFactory emf = null;
         OpenJPAEntityManager em = null;
         Integer setTime = new Integer(0);        
+        boolean bRetry = true;
 
         try {
             // create our EMF with our PU set timeout property
@@ -646,8 +653,7 @@
             //    "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");
+            OpenJPAQuery q = em.createNativeQuery(nativeUpdateStr);
             q.setParameter(1, new String("updated"));
             // verify no default javax.persistence.query.timeout is supplied
             Map<String, Object> hints = q.getHints();
@@ -666,21 +672,32 @@
             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);
+            em.getTransaction().begin();
+            for (int i=0; i<=1 && bRetry; i++)
+            {
+                try {
+                    long startTime = System.currentTimeMillis();
+                    @SuppressWarnings("unused")
+                    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, MS SQL
+                    // should only retry the statement if db did not rollback
+                    // which should be a QueryTimeoutException
+                    bRetry = checkException("testQueryTimeout33c()", e);
+                    // we're only retrying to prove the right exception type
+                    // was thrown and the transaction wasn't rolled back
+                    if (bRetry)
+                        getLog().trace("testQueryTimeout33c() - retrying... ");
+                }
             }
         } finally {
             if ((em != null) && em.isOpen()) {
@@ -699,6 +716,8 @@
      */
     public void testQueryTimeout4() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout4 - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         Integer setTime = new Integer(-1);
@@ -755,9 +774,6 @@
      * Expected Results: IllegalArgumentException
      */
     public void testQueryTimeout5() {
-        if (skipTests) {
-            return;
-        }
         Integer setTime = new Integer(-2000);
         getLog().trace("testQueryTimeout5() - setHint(" + setTime + ")");
         EntityManager em = null;
@@ -778,7 +794,7 @@
             fail("Expected testQueryTimeout5() to throw a " + 
                 "IllegalArgumentException");
         } catch (Exception e) {
-            // expected - setHint(-2000) should cause an IllegalArgumentException
+            // expected - setHint(-2000) should cause IllegalArgumentException
             checkException("testQueryTimeout5()", e, 
                 IllegalArgumentException.class, "invalid timeout of -2,000");
         } finally {
@@ -796,6 +812,8 @@
      */
     public void testQueryTimeout6() {
         if (skipTests) {
+            getLog().trace("testQueryTimeout6 - test is " +
+                "being skipped for " + dict.platform);
             return;
         }
         getLog().trace("testQueryTimeout6() - No EM.find() update timeout");
@@ -847,6 +865,139 @@
         }
     }
 
+    
+    /**
+     * Internal setup convenience method to create some entities for testing
+     */
+    private void setupCreateEntities() {
+        getLog().trace("setupCreateEntities()");
+        String[] _strings = new String[] { "a", "b", "c" };
+        QTimeout qt = null;
+        EntityManager em = null;
+
+        // create some initial entities
+        try {
+            em = emf.createEntityManager();
+            assertNotNull(em);
+            getLog().trace("setupCreateEntities() - creating 3 Qtimeout");
+            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("setupCreateEntities() - Unexpected Exception - " + e);
+        } finally {
+            if ((em != null) && em.isOpen()) {
+                em.close();
+            }
+        }
+    }
+    
+    /**
+     * Create delay function only on Derby, other DBs require manual setup
+     */
+    private void setupCreateDBFunction() {
+        if (dict instanceof DerbyDictionary) {
+            getLog().trace("setupCreateDBFunction()");
+            // 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());
+            }
+        } else {
+            getLog().trace("setupCreateDBFunction() - skipping as DB != Derby");
+        }
+    }
+    
+    /**
+     * Create triggers on all DBs
+     * @param dict
+     * @return boolean - true if successful, otherwise false
+     */
+    private boolean setupCreateDBTriggers() {
+        boolean brc = false;
+        getLog().trace("setupCreateDBTriggers()");
+        // create triggers on all DBs
+        try {
+            if ((dict instanceof DerbyDictionary) ||
+                (dict instanceof DB2Dictionary)) {
+                getLog().trace("setupCreateDBTriggers() - creating BEFORE " +
+                    "TRIGGER for Derby and DB2");
+                exec(true, 0, "DROP TRIGGER t1");
+                // DB2 needs multiple connections and longer delays to timeout
+                exec(false, 0, "CREATE TRIGGER t1 NO CASCADE BEFORE UPDATE " +
+                    "ON qtimeout FOR EACH ROW MODE DB2SQL values DELAY(2,-1)");
+                // exec(true, 0, "DROP TRIGGER t2");
+                // 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 - slows down the DROP_TABLES
+                // cleanup between tests
+                // exec(false, 0, "CREATE TRIGGER t3 NO CASCADE BEFORE DELETE "+
+                //   "ON qtimeout FOR EACH ROW MODE DB2SQL values DELAY(2,-3)");
+                brc = true;
+            } else if (dict instanceof SQLServerDictionary) {
+                // These may have already been created by the DDL
+                getLog().trace("setupCreateDBTriggers() - creating BEFORE " +
+                    "UPDATE TRIGGER for MS SQL Server");
+                exec(true, 0, "DROP TRIGGER t1");
+                exec(false, 0, "CREATE TRIGGER t1 ON QTimeout FOR UPDATE " +
+                    "AS EXTERNAL NAME Delay.Delay.delay");
+                // exec(true, 0, "DROP TRIGGER t2");
+                // exec(false, 0, "CREATE OR REPLACE TRIGGER t2 ON QTimeout " +
+                //     "FOR INSERT AS EXTERNAL NAME Delay.Delay.delay");
+                brc = true;
+            } else if (dict instanceof OracleDictionary) {
+                // These may have already been created by the DDL
+                getLog().trace("setupCreateDBTriggers() - creating BEFORE " +
+                    "UPDATE TRIGGER for Oracle");
+                exec(false, 0, "CREATE OR REPLACE TRIGGER \"OPENJPA\".T1 " +
+                    "BEFORE UPDATE OF \"ID\", \"STRINGFIELD\", " +
+                    "\"VERSIONFIELD\" ON \"OPENJPA\".\"QTIMEOUT\" CALL DELAY");
+                // exec(false, 0, "CREATE OR REPLACE TRIGGER \"OPENJPA\".T2 " +
+                //     "BEFORE INSERT ON \"OPENJPA\".\"QTIMEOUT\" CALL DELAY");
+                brc = true;
+            } else if (dict instanceof InformixDictionary) {
+                // These may have already been created by the DDL
+                getLog().trace("setupCreateDBTriggers() - creating BEFORE " +
+                    "UPDATE TRIGGER for Informix");
+                exec(true, 0, "DROP TRIGGER t1");
+                // exec(false, 0, "CREATE TRIGGER t1 UPDATE " +
+                //     "of Id, stringField, versionField ON QTimeout " +
+                //     "BEFORE(EXECUTE FUNCTION delay(5,-1))");
+                exec(false, 0, "CREATE TRIGGER t1 UPDATE " +
+                    "of Id, stringField, versionField ON QTimeout " +
+                    "BEFORE(EXECUTE PROCEDURE delay5())");
+                brc = true;
+            } else {
+                getLog().info("TestQueryTimeout tests are being skipped as " +
+                    "triggers were not created for " + dict.platform);
+            }
+        } 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.  " + dict.platform +
+                    " requires manual setup steps for these tests.");
+                getLog().trace("setupCreateDBTriggers() failed with " +
+                    "SQLException = ", sqe);
+            }
+        }
+        return brc;
+    }
+    
     /**
      * Internal convenience method to execute SQL statements
      * 
@@ -904,14 +1055,19 @@
      * 
      * @param test
      * @param e
+     * @return boolean indicating if operation can be retried
      */
-    private void checkException(String test, Exception e) {
+    private boolean checkException(String test, Exception e) {
         String eStr = new String("query statement timeout");
+        boolean bRetry = matchesExpectedException(QueryTimeoutException.class,
+            e, eStr);
+        boolean bRollback = matchesExpectedException(PersistenceException.class,
+            e, eStr);
         // no easy way to determine exact Exception type for all DBs
         assertTrue(test + " - UNEXPECTED Exception = " + e,
-            matchesExpectedException(QueryTimeoutException.class, e, eStr) ||
-            matchesExpectedException(PersistenceException.class, e, eStr));
-        getLog().trace(test + " - Caught expected Exception = " + e);
+            (bRetry || bRollback));
+        getLog().trace(test + " - Caught expected Exception = ", e);
+        return bRetry;
     }
 
     /**
@@ -923,11 +1079,11 @@
      * @param expected exception type
      * @param eStr an optional substring to match in the exception text
      */
-    private void checkException(String test, Exception tested, Class expected, 
-        String eStr) {
+    private void checkException(String test, Exception tested,
+        Class<?> expected, String eStr) {
         assertTrue(test + " - UNEXPECTED Exception = " + tested,
             matchesExpectedException(expected, tested, eStr));
-        getLog().trace(test + " - Caught expected Exception = " + tested);
+        getLog().trace(test + " - Caught expected Exception = ", tested);
     }
 
     /**



Mime
View raw message