=== modified file 'CHANGES' --- CHANGES 2009-03-25 20:03:28 +0000 +++ CHANGES 2009-04-13 03:50:09 +0000 @@ -39,6 +39,9 @@ long as there is no use of LAST_INSERT_ID() in the update clause (as this would render getGeneratedKey() values incorrect). + - Fixed Bug #39426 - executeBatch passes most recent PreparedStatement params + to StatementInterceptor + 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' --- src/com/mysql/jdbc/PreparedStatement.java 2009-03-25 20:01:00 +0000 +++ src/com/mysql/jdbc/PreparedStatement.java 2009-04-09 20:49:23 +0000 @@ -531,6 +531,9 @@ private boolean compensateForOnDuplicateKeyUpdate = false; + /** Command index of currently executing batch command. */ + private int batchCommandIndex = -1; + /** * Creates a prepared statement instance -- We need to provide factory-style * methods so we can support both JDBC3 (and older) and JDBC4 runtimes, @@ -724,6 +727,9 @@ try { int realParameterCount = this.parameterCount + getParameterIndexOffset(); + Object batchArg = null; + if (batchCommandIndex != -1) + batchArg = batchedArgs.get(batchCommandIndex); for (int i = 0; i < realParameterCount; ++i) { if (this.charEncoding != null) { @@ -733,7 +739,23 @@ buf.append(new String(this.staticSqlStrings[i])); } - if ((this.parameterValues[i] == null) && !this.isStream[i]) { + byte val[] = null; + if (batchArg != null && batchArg instanceof String) { + buf.append((String)batchArg); + continue; + } + if (batchCommandIndex == -1) + val = parameterValues[i]; + else + val = ((BatchParams)batchArg).parameterStrings[i]; + + boolean isStreamParam = false; + if (batchCommandIndex == -1) + isStreamParam = isStream[i]; + else + isStreamParam = ((BatchParams)batchArg).isStream[i]; + + if ((val == null) && !isStreamParam) { if (quoteStreamsAndUnknowns) { buf.append("'"); } @@ -743,7 +765,7 @@ if (quoteStreamsAndUnknowns) { buf.append("'"); } - } else if (this.isStream[i]) { + } else if (isStreamParam) { if (quoteStreamsAndUnknowns) { buf.append("'"); } @@ -755,15 +777,12 @@ } } else { if (this.charConverter != null) { - buf.append(this.charConverter - .toString(this.parameterValues[i])); + buf.append(this.charConverter.toString(val)); } else { if (this.charEncoding != null) { - buf.append(new String(this.parameterValues[i], - this.charEncoding)); + buf.append(new String(val, this.charEncoding)); } else { - buf.append(StringUtils - .toAsciiString(this.parameterValues[i])); + buf.append(StringUtils.toAsciiString(val)); } } } @@ -1636,8 +1655,6 @@ SQLException sqlEx = null; - int commandIndex = 0; - CancelTask timeoutTask = null; try { @@ -1653,16 +1670,16 @@ this.batchedGeneratedKeys = new ArrayList(nbrCommands); } - for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) { - Object arg = this.batchedArgs.get(commandIndex); + for (batchCommandIndex = 0; batchCommandIndex < nbrCommands; batchCommandIndex++) { + Object arg = this.batchedArgs.get(batchCommandIndex); if (arg instanceof String) { - updateCounts[commandIndex] = executeUpdate((String) arg); + updateCounts[batchCommandIndex] = executeUpdate((String) arg); } else { BatchParams paramArg = (BatchParams) arg; try { - updateCounts[commandIndex] = executeUpdate( + updateCounts[batchCommandIndex] = executeUpdate( paramArg.parameterStrings, paramArg.parameterStreams, paramArg.isStream, paramArg.streamLengths, paramArg.isNull, true); @@ -1687,7 +1704,7 @@ } } } catch (SQLException ex) { - updateCounts[commandIndex] = EXECUTE_FAILED; + updateCounts[batchCommandIndex] = EXECUTE_FAILED; if (this.continueBatchOnError && !(ex instanceof MySQLTimeoutException) && @@ -1695,9 +1712,9 @@ !hasDeadlockOrTimeoutRolledBackTx(ex)) { sqlEx = ex; } else { - int[] newUpdateCounts = new int[commandIndex]; + int[] newUpdateCounts = new int[batchCommandIndex]; System.arraycopy(updateCounts, 0, - newUpdateCounts, 0, commandIndex); + newUpdateCounts, 0, batchCommandIndex); throw new java.sql.BatchUpdateException(ex .getMessage(), ex.getSQLState(), ex @@ -1712,6 +1729,8 @@ sqlEx.getSQLState(), sqlEx.getErrorCode(), updateCounts); } } finally { + batchCommandIndex = -1; + if (timeoutTask != null) { timeoutTask.cancel(); } @@ -2320,6 +2339,49 @@ return parameterVal; } + + /** + * Get bytes representation for a parameter in a statement batch. + * @param parameterIndex + * @param commandIndex + * @return + * @throws SQLException + */ + protected byte[] getBytesRepresentationForBatch(int parameterIndex, int commandIndex) + throws SQLException { + Object batchedArg = batchedArgs.get(commandIndex); + if (batchedArg instanceof String) { + try { + return ((String)batchedArg).getBytes(charEncoding); + + } catch (UnsupportedEncodingException uue) { + throw new RuntimeException(Messages + .getString("PreparedStatement.32") //$NON-NLS-1$ + + this.charEncoding + + Messages.getString("PreparedStatement.33")); //$NON-NLS-1$ + } + } + + BatchParams params = (BatchParams)batchedArg; + if (params.isStream[parameterIndex]) + return streamToBytes(params.parameterStreams[parameterIndex], false, + params.streamLengths[parameterIndex], + connection.getUseStreamLengthsInPrepStmts()); + byte parameterVal[] = params.parameterStrings[parameterIndex]; + if (parameterVal == null) + return null; + + if ((parameterVal[0] == '\'') + && (parameterVal[parameterVal.length - 1] == '\'')) { + byte[] valNoQuotes = new byte[parameterVal.length - 2]; + System.arraycopy(parameterVal, 1, valNoQuotes, 0, + parameterVal.length - 2); + + return valNoQuotes; + } + + return parameterVal; + } // --------------------------JDBC 2.0----------------------------- @@ -5091,7 +5153,10 @@ Field[] typeMetadata = new Field[parameterCount]; for (int i = 0; i < parameterCount; i++) { - rowData[i] = getBytesRepresentation(i); + if (batchCommandIndex == -1) + rowData[i] = getBytesRepresentation(i); + else + rowData[i] = getBytesRepresentationForBatch(i, batchCommandIndex); int charsetIndex = 0; === modified file 'src/testsuite/regression/StatementRegressionTest.java' --- src/testsuite/regression/StatementRegressionTest.java 2009-03-26 01:29:57 +0000 +++ src/testsuite/regression/StatementRegressionTest.java 2009-04-09 20:45:48 +0000 @@ -58,7 +58,9 @@ import java.sql.Timestamp; import java.sql.Types; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; @@ -68,10 +70,12 @@ import com.mysql.jdbc.CachedResultSetMetaData; import com.mysql.jdbc.Field; +import com.mysql.jdbc.ParameterBindings; import com.mysql.jdbc.ResultSetInternalMethods; import com.mysql.jdbc.SQLError; import com.mysql.jdbc.ServerPreparedStatement; import com.mysql.jdbc.StatementImpl; +import com.mysql.jdbc.StatementInterceptor; import com.mysql.jdbc.exceptions.MySQLTimeoutException; /** @@ -5905,4 +5909,66 @@ closeMemberJDBCResources(); } } + + public static class Bug39426Interceptor implements StatementInterceptor { + public static List vals = new ArrayList(); + String prevSql; + + public void destroy() { + } + + public boolean executeTopLevelOnly() { + return false; + } + + public void init(com.mysql.jdbc.Connection conn, Properties props) + throws SQLException { + } + + public ResultSetInternalMethods postProcess(String sql, + com.mysql.jdbc.Statement interceptedStatement, + ResultSetInternalMethods originalResultSet, + com.mysql.jdbc.Connection connection) throws SQLException { + return null; + } + + public ResultSetInternalMethods preProcess(String sql, + com.mysql.jdbc.Statement interceptedStatement, + com.mysql.jdbc.Connection connection) throws SQLException { + if (sql.equals(prevSql)) + throw new RuntimeException("Previous statement matched current: " + sql); + prevSql = sql; + ParameterBindings b = ((com.mysql.jdbc.PreparedStatement)interceptedStatement).getParameterBindings(); + vals.add(new Integer(b.getInt(1))); + return null; + } + } + + /** + * Bug #39426 - executeBatch passes most recent PreparedStatement params + * to StatementInterceptor + */ + public void testBug39426() throws Exception { + Connection c = null; + try { + createTable("testBug39426", "(x int)"); + c = getConnectionWithProps("statementInterceptors=testsuite.regression.StatementRegressionTest$Bug39426Interceptor"); + PreparedStatement ps = c.prepareStatement("insert into testBug39426 values (?)"); + ps.setInt(1, 1); + ps.addBatch(); + ps.setInt(1, 2); + ps.addBatch(); + ps.setInt(1, 3); + ps.addBatch(); + ps.executeBatch(); + List vals = Bug39426Interceptor.vals; + assertEquals(new Integer(1), vals.get(0)); + assertEquals(new Integer(2), vals.get(1)); + assertEquals(new Integer(3), vals.get(2)); + } finally { + closeMemberJDBCResources(); + if(c != null) + c.close(); + } + } } \ No newline at end of file