List:Commits« Previous MessageNext Message »
From:mark Date:December 1 2008 9:39pm
Subject:bzr push into connector-j/branches/branch_5_1 branch (mark:756 to 758)
Bug#41161
View as plain text  
  758 mark@stripped	2008-12-01
      Fixed BUG#41161 - PreparedStatement.addBatch() doesn't check for all parameters
       being set, which leads to a NullPointerException when calling executeBatch() and
       rewriting batched statements into multi-value or multi-statement statements.
modified:
  CHANGES
  src/com/mysql/jdbc/PreparedStatement.java
  src/testsuite/regression/StatementRegressionTest.java

  757 mark@stripped	2008-12-01
      Cleaner implementation of indexOfIgnoreCase().
modified:
  src/com/mysql/jdbc/StringUtils.java

  756 mark@stripped	2008-11-11
      Disable nanos/micros for now
modified:
  src/com/mysql/jdbc/PreparedStatement.java

=== modified file 'CHANGES'
--- a/CHANGES	2008-10-20 21:28:59 +0000
+++ b/CHANGES	2008-12-01 21:38:32 +0000
@@ -1,6 +1,10 @@
 # Changelog
 # $Id$
-
+nn-nn-08 - Version 5.1.8
+    - Fixed BUG#41161 - PreparedStatement.addBatch() doesn't check for all parameters
+      being set, which leads to a NullPointerException when calling executeBatch() and
+      rewriting batched statements into multi-value or multi-statement statements.
+      
 10-22-08 - Version 5.1.7
 	- Fixed BUG#33861 - Added global blacklist for LoadBalancingConnectionProxy and
 	  implemented in RandomBalanceStrategy and BestResponseTimeBalanceStrategy.

=== modified file 'src/com/mysql/jdbc/PreparedStatement.java'
--- a/src/com/mysql/jdbc/PreparedStatement.java	2008-11-11 07:03:11 +0000
+++ b/src/com/mysql/jdbc/PreparedStatement.java	2008-12-01 21:38:32 +0000
@@ -692,6 +692,11 @@ public class PreparedStatement extends c
 			this.batchedArgs = new ArrayList();
 		}
 
+		for (int i = 0; i < this.parameterValues.length; i++) {
+			checkAllParametersSet(this.parameterValues[i],
+					this.parameterStreams[i], i);
+		}
+		
 		this.batchedArgs.add(new BatchParams(this.parameterValues,
 				this.parameterStreams, this.isStream, this.streamLengths,
 				this.isNull));
@@ -2209,12 +2214,8 @@ public class PreparedStatement extends c
 		}
 		
 		for (int i = 0; i < batchedParameterStrings.length; i++) {
-			if ((batchedParameterStrings[i] == null)
-					&& (batchedParameterStreams[i] == null)) {
-				throw SQLError.createSQLException(Messages
-						.getString("PreparedStatement.40") //$NON-NLS-1$
-						+ (i + 1), SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS, getExceptionInterceptor());
-			}
+			checkAllParametersSet(batchedParameterStrings[i],
+					batchedParameterStreams[i], i);
 
 			sendPacket.writeBytesNoNull(this.staticSqlStrings[i]);
 
@@ -2232,6 +2233,16 @@ public class PreparedStatement extends c
 		return sendPacket;
 	}
 
+	private void checkAllParametersSet(byte[] parameterString,
+			InputStream parameterStream, int columnIndex) throws SQLException {
+		if ((parameterString == null)
+				&& parameterStream == null) {
+			throw SQLError.createSQLException(Messages
+					.getString("PreparedStatement.40") //$NON-NLS-1$
+					+ (columnIndex + 1), SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS, getExceptionInterceptor());
+		}
+	}
+
 	private String generateBatchedInsertSQL(String valuesClause, int numBatches) {
 		StringBuffer newStatementSql = new StringBuffer(this.originalSql
 				.length()

=== modified file 'src/com/mysql/jdbc/StringUtils.java'
--- a/src/com/mysql/jdbc/StringUtils.java	2008-11-11 06:19:59 +0000
+++ b/src/com/mysql/jdbc/StringUtils.java	2008-12-01 20:40:15 +0000
@@ -929,8 +929,6 @@ public class StringUtils {
 		int stringLength = searchIn.length();
 		int stopSearchingAt = stringLength - patternLength;
 
-		int i = startingPosition;
-
 		if (patternLength == 0) {
 			return -1;
 		}
@@ -940,49 +938,38 @@ public class StringUtils {
 		char firstCharOfPatternUc = Character.toUpperCase(searchFor.charAt(0));
 		char firstCharOfPatternLc = Character.toLowerCase(searchFor.charAt(0));
 
-		lookForFirstChar: while (true) {
-			while ((i < stopSearchingAt)
-					&& (Character.toUpperCase(searchIn.charAt(i)) != firstCharOfPatternUc)
-					&& Character.toLowerCase(searchIn.charAt(i)) != firstCharOfPatternLc) {
-				i++;
-			}
-
-			if (i > stopSearchingAt) {
-				return -1;
-			}
-
-			int j = i + 1;
-			int end = (j + patternLength) - 1;
-
-			int k = 1; // start at second char of pattern
-
-			while (j < end) {
-				int searchInPos = j++;
-				int searchForPos = k++;
-
-				if (Character.toUpperCase(searchIn.charAt(searchInPos)) != Character
-						.toUpperCase(searchFor.charAt(searchForPos))) {
-					i++;
-
-					// start over
-					continue lookForFirstChar;
-				}
-
-				// Georgian and Turkish locales don't have same convention, so
-				// need to check lowercase
-				// too!
-				if (Character.toLowerCase(searchIn.charAt(searchInPos)) != Character
-						.toLowerCase(searchFor.charAt(searchForPos))) {
-					i++;
-
-					// start over
-					continue lookForFirstChar;
-				}
-			}
-
-			return i; // found entire pattern
-		}
+		// note, this also catches the case where patternLength > stringLength
+        for (int i = startingPosition; i <= stopSearchingAt; i++) {
+            if (isNotEqualIgnoreCharCase(searchIn, firstCharOfPatternUc,
+					firstCharOfPatternLc, i)) {
+            	// find the first occurrence of the first character of searchFor in searchIn
+                while (++i <= stopSearchingAt && (isNotEqualIgnoreCharCase(searchIn, firstCharOfPatternUc,
+						firstCharOfPatternLc, i)));
+            }
+
+            if (i <= stopSearchingAt /* searchFor might be one character long! */) {
+            	// walk searchIn and searchFor in lock-step starting just past the first match,bail out if not 
+            	// a match, or we've hit the end of searchFor...
+                int j = i + 1;
+                int end = j + patternLength - 1;
+                for (int k = 1; j < end && (Character.toLowerCase(searchIn.charAt(j)) == 
+                	Character.toLowerCase(searchFor.charAt(k)) || Character.toUpperCase(searchIn.charAt(j)) == 
+                    	Character.toUpperCase(searchFor.charAt(k))); j++, k++);
+
+                if (j == end) {
+                    return i;
+                }
+            }
+        }
+        
+        return -1;
+	}
+
+	private final static boolean isNotEqualIgnoreCharCase(String searchIn,
+			char firstCharOfPatternUc, char firstCharOfPatternLc, int i) {
+		return Character.toLowerCase(searchIn.charAt(i)) != firstCharOfPatternLc && Character.toUpperCase(searchIn.charAt(i)) != firstCharOfPatternUc;
 	}
+	
 
 	/**
 	 * DOCUMENT ME!

=== modified file 'src/testsuite/regression/StatementRegressionTest.java'
--- a/src/testsuite/regression/StatementRegressionTest.java	2008-11-11 06:19:18 +0000
+++ b/src/testsuite/regression/StatementRegressionTest.java	2008-12-01 21:38:32 +0000
@@ -5659,4 +5659,29 @@ public class StatementRegressionTest ext
 			closeMemberJDBCResources();
 		}
 	}
+	
+	public void testBug41161() throws Exception {
+		createTable("testBug41161", "(a int, b int)");
+		
+		Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true");
+		
+		try {
+			this.pstmt = rewriteConn.prepareStatement("INSERT INTO testBug41161 (a, b) VALUES (?, ?, ?)");
+			this.pstmt.setInt(1, 1);
+			this.pstmt.setInt(2, 1);
+			
+			try {
+				this.pstmt.addBatch();
+				fail("Should have thrown an exception");
+			} catch (SQLException sqlEx) {
+				assertEquals("07001", sqlEx.getSQLState());
+			}
+			
+			this.pstmt.executeBatch(); // NPE when this bug exists
+		} finally {
+			closeMemberJDBCResources();
+			
+			rewriteConn.close();
+		}
+	}
  } 
\ No newline at end of file

Thread
bzr push into connector-j/branches/branch_5_1 branch (mark:756 to 758)Bug#41161mark1 Dec