You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by my...@apache.org on 2008/10/02 00:07:49 UTC

svn commit: r700948 - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ drda/org/apache/derby/impl/drda/ engine/org/apache/derby/iapi/services/i18n/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/fu...

Author: myrnavl
Date: Wed Oct  1 15:07:48 2008
New Revision: 700948

URL: http://svn.apache.org/viewvc?rev=700948&view=rev
Log:
DERBY-3390; preventing ClassCastException and disconnect on SQLException thrown from a user function

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Sqlca.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/i18n/MessageService.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/GetPropertyInfoTest.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/SqlExceptionTest.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Sqlca.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/Sqlca.java?rev=700948&r1=700947&r2=700948&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Sqlca.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Sqlca.java Wed Oct  1 15:07:48 2008
@@ -390,8 +390,9 @@
                 // (five characters) and a colon. Extract the SQL state and
                 // clean up the token. See
                 // DRDAConnThread.buildTokenizedSqlerrmc() for more details.
-                states[i] = tokens[i].substring(0, 5);
-                tokens[i] = tokens[i].substring(6);
+                int colonpos = tokens[i].indexOf(":");
+                states[i] = tokens[i].substring(0, colonpos);
+                tokens[i] = tokens[i].substring(colonpos + 1);
             }
             sqlStates_ = states;
             sqlErrmcMessages_ = tokens;

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=700948&r1=700947&r2=700948&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Wed Oct  1 15:07:48 2008
@@ -6005,7 +6005,7 @@
 		se = Util.getExceptionFactory().getArgumentFerry( se );
 		
 		if (se instanceof EmbedSQLException  && ! severe)
-			sqlerrmc = buildTokenizedSqlerrmc((EmbedSQLException) se);
+			sqlerrmc = buildTokenizedSqlerrmc(se);
 		else {
 			// If this is not an EmbedSQLException or is a severe excecption where
 			// we have no hope of succussfully calling the SYSIBM.SQLCAMESSAGE send
@@ -6057,17 +6057,32 @@
 	 * @param se   SQLException to print
 	 * 
 	 */
-	private String buildTokenizedSqlerrmc(EmbedSQLException se) {
+	private String buildTokenizedSqlerrmc(SQLException se) {
 		
 		String sqlerrmc = "";
 		do {
-			String messageId = se.getMessageId();
-			// arguments are variable part of a message
-			Object[] args = se.getArguments();
-			for (int i = 0; args != null &&  i < args.length; i++)
-				sqlerrmc += args[i] + SQLERRMC_TOKEN_DELIMITER;
-			sqlerrmc += messageId;
-			se = (EmbedSQLException) se.getNextException();
+			if ( se instanceof EmbedSQLException)
+			{
+				String messageId = ((EmbedSQLException)se).getMessageId();
+				// arguments are variable part of a message
+				Object[] args = ((EmbedSQLException)se).getArguments();
+				for (int i = 0; args != null &&  i < args.length; i++)
+					sqlerrmc += args[i] + SQLERRMC_TOKEN_DELIMITER;
+				sqlerrmc += messageId;
+				se = se.getNextException();
+			}
+			else
+			{   
+				// this could happen for instance if an SQLException was thrown
+				// from a stored procedure.
+				StringBuffer sb = new StringBuffer(); 
+				sb.append(se.getLocalizedMessage());
+				se = se.getNextException();
+				if (se != null)
+				sb.append(SQLERRMC_TOKEN_DELIMITER + 
+					"SQLSTATE: " + se.getSQLState());
+				sqlerrmc += sb.toString();
+			}
 			if (se != null)
 			{
 				sqlerrmc += SystemProcedures.SQLERRMC_MESSAGE_DELIMITER + se.getSQLState() + ":";				

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/i18n/MessageService.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/i18n/MessageService.java?rev=700948&r1=700947&r2=700948&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/i18n/MessageService.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/i18n/MessageService.java Wed Oct  1 15:07:48 2008
@@ -270,8 +270,9 @@
 		
 		StringBuffer sb = new StringBuffer(messageId);
 
-		sb.append(" : ");
 		int len = arguments.length;
+		if (len > 0)
+			sb.append(" : ");
 
 		for (int i=0; i < len; i++) {
 		    // prepend a comma to all but the first

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/GetPropertyInfoTest.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/GetPropertyInfoTest.out?rev=700948&r1=700947&r2=700948&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/GetPropertyInfoTest.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/GetPropertyInfoTest.out Wed Oct  1 15:07:48 2008
@@ -9,8 +9,8 @@
 user - value: null - description: user name - required false - choices null 
 logDevice - value: null - description: log directory path - required false - choices null 
 rollForwardRecoveryFrom - value: null - description: backup path for rollforward recovery - required false - choices null 
-createFrom - value: null - description: J029 :  - required false - choices null 
-restoreFrom - value: null - description: J030 :  - required false - choices null 
+createFrom - value: null - description: J029 - required false - choices null 
+restoreFrom - value: null - description: J030 - required false - choices null 
 bootPassword - value:  - description: secret cryptographic key - required false - choices null 
 password - value:  - description: user password - required false - choices null 
 shutdown - value: false - description: shut down Derby - required false     - choices [0] : false     - choices [1] : true
@@ -27,8 +27,8 @@
 user - value: null - description: user name - required false - choices null 
 logDevice - value: null - description: log directory path - required false - choices null 
 rollForwardRecoveryFrom - value: null - description: backup path for rollforward recovery - required false - choices null 
-createFrom - value: null - description: J029 :  - required false - choices null 
-restoreFrom - value: null - description: J030 :  - required false - choices null 
+createFrom - value: null - description: J029 - required false - choices null 
+restoreFrom - value: null - description: J030 - required false - choices null 
 bootPassword - value: **** - description: secret cryptographic key - required false - choices null 
 password - value:  - description: user password - required false - choices null 
 shutdown - value: false - description: shut down Derby - required false     - choices [0] : false     - choices [1] : true

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/SqlExceptionTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/SqlExceptionTest.java?rev=700948&r1=700947&r2=700948&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/SqlExceptionTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/SqlExceptionTest.java Wed Oct  1 15:07:48 2008
@@ -143,6 +143,87 @@
             assertSQLExceptionEquals(se, se_ser);
         }
     }
+    
+    /**
+     * Verify that an SQLException thrown by a function can be returned
+     * (DERBY-790).
+     */
+    public void testDerby3390() throws Exception {
+        setAutoCommit(false);
+        Statement stmt = createStatement();
+
+        // with client/server we prefetch, so the error comes earlier
+        try {
+            if (usingDerbyNetClient())
+            {
+                stmt.execute("values badFunction1()");
+                fail("expected an error");
+            }
+            else 
+            {
+                stmt.execute("values badFunction1()");
+                ResultSet rs = stmt.getResultSet();
+                rs.next();
+                fail("expected an error");
+            }
+        } catch (SQLException e) {
+            setAutoCommit(true);
+            // if DERBY-3390 occurs, at this point, with networkserver/client, 
+            // we'd get a 08006. In the server's derby.log you'd see a 
+            // ClassCastException
+            assertSQLState("38000", e);
+            assertTrue(e.getMessage().indexOf("I refuse to return an int") > 1);
+        }
+
+        // as above, but this time the function uses the constructor for
+        // SQLException with SQLState.
+        try {
+            if (usingDerbyNetClient())
+            {
+                stmt.execute("values badFunction2()");
+                fail("expected an error");
+            }
+            else 
+            {
+                stmt.execute("values badFunction2()");
+                ResultSet rs = stmt.getResultSet();
+                rs.next();
+                fail("expected an error");
+            }
+        } catch (SQLException e) {
+            setAutoCommit(true);
+            // if DERBY-3390 occurs, at this point, with networkserver/client, 
+            // we'd get a 08006. In the server's derby.log you'd see a 
+            // ClassCastException
+            assertSQLState("38000", e);
+            assertSQLState("50000", e);
+            assertTrue(e.getMessage().indexOf("I refuse to return an int") > 1);
+        }
+
+        // test an Exception gets thrown for good measure
+        try {
+            if (usingDerbyNetClient())
+            {
+                stmt.execute("values badFunction3()");
+                fail("expected an error");
+            }
+            else 
+            {
+                stmt.execute("values badFunction3()");
+                ResultSet rs = stmt.getResultSet();
+                rs.next();
+                fail("expected an error");
+            }
+        } catch (SQLException e) {
+            setAutoCommit(true);
+            assertSQLState("38000", e);
+            assertTrue(e.getMessage().indexOf("The exception 'java.lang.Exception: I refuse to return an int!'")==0);
+        }
+        
+        stmt.close();
+        rollback();
+        setAutoCommit(true);
+    }    
 
     /**
      * Set up the connection to the database.
@@ -154,6 +235,15 @@
                 "c2 int)";
         Statement stmt = conn.createStatement();
         stmt.execute(createTableWithPK);
+        stmt.execute("create function badFunction1() returns int language java"
+                + " parameter style java no sql external name '" +
+                SqlExceptionTest.class.getName() + ".badFunction1'");
+        stmt.execute("create function badFunction2() returns int language java"
+                + " parameter style java no sql external name '" +
+                SqlExceptionTest.class.getName() + ".badFunction2'");
+        stmt.execute("create function badFunction3() returns int language java"
+                + " parameter style java no sql external name '" +
+                SqlExceptionTest.class.getName() + ".badFunction3'");
         stmt.close();
         conn.close();
     }
@@ -165,6 +255,9 @@
         Connection conn = getConnection();
         Statement stmt = conn.createStatement();
         stmt.executeUpdate("DROP TABLE tableWithPK");
+        stmt.executeUpdate("drop function badfunction1");
+        stmt.executeUpdate("drop function badfunction2");
+        stmt.executeUpdate("drop function badfunction3");
         stmt.close();
         conn.close();
         super.tearDown();
@@ -204,4 +297,38 @@
             return test;
         }
     }
+    
+    /* <p> 
+     * For testing DERBY-3390
+     * This function just throws a SQLException, without SQLState 
+     * </p> 
+     */ 
+    public static int badFunction1() 
+        throws SQLException 
+    { 
+        throw new SQLException( "I refuse to return an int!" );
+    }
+
+    /* <p> 
+     * For testing DERBY-3390
+     * This function just throws a SQLException, with SQLState 
+     * </p> 
+     */ 
+    public static int badFunction2() 
+        throws SQLException 
+    { 
+        throw new SQLException( "I refuse to return an int!", "50000" );
+    }
+    
+    /* <p> 
+     * For testing DERBY-3390
+     * This function just throws an Exception 
+     * </p> 
+     */ 
+    public static int badFunction3() 
+        throws Exception 
+    { 
+        throw new Exception( "I refuse to return an int!" );
+    }
+
 }