| Bug #46788 | While using ON DUPLICATE KEY UPDATE on a batchRewriteStatements I get exception | ||
|---|---|---|---|
| Submitted: | 18 Aug 2009 14:58 | Modified: | 16 Sep 2009 13:42 | 
| Reporter: | Dan Dumitriu | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | Connector / J | Severity: | S2 (Serious) | 
| Version: | 5.1.8 | OS: | Linux (Fedora 10) | 
| Assigned to: | Mark Matthews | CPU Architecture: | Any | 
| Tags: | exception, ON DUPLICATE KEY UPDATE, Parameter index out of range | ||
   [18 Aug 2009 15:08]
   Mark Matthews        
  Versions prior to 5.1.8 wouldn't attempt to re-write a query of this form as a multi-value INSERT. 5.1.8 will attempt to re-write this query as a multi-value INSERT. It seems we'll need a check that there are no parameters after the ON DUPLICATE KEY UPDATE clause, because it's not possible to re-write the query into a multi-value INSERT. Instead it should be sent as a multi-query (as it was prior to 5.1.8).
   [18 Aug 2009 16:01]
   Dan Dumitriu        
  Hi, Actually I was hopping I will get this fix and still aim for some performance improvement. As I found in a presentation (ConnectorJ Performance) by someone called Mark Matthews ;) A Rewritten INSERT INSERT INTO foo VALUES (...),(...),(...) up to max_allowed_packet Starting in 5.1.8, ON DUPLICATE KEY UPDATE rewritten into multi-value as well! except for case where you use LAST_INSERT_ID() I do not know if that is technically possible or not. Dan
   [18 Aug 2009 19:01]
   Mark Matthews        
  The issue is that the query can not be re-written to a form like: INSERT INTO foo VALUES (...), (...), (...) ON DUPLICATE KEY UPDATE ... because after the update the query has parameters. There is no form of multi-value INSERT that works for that case. The entire batch could be re-written to a form like: INSERT INTO foo VALUES (...) ON DUPLICATE KEY UPDATE bar=1; INSERT INTO foo VALUES (...) ON DUPLICATE KEY UPDATE bar=2; Which is what the fix will have to be. You might consider if the query can be re-written to not require a parameter in the UPDATE clause, i.e. using the VALUES function, see http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
   [26 Aug 2009 14:50]
   Mark Matthews        
  Fixed for 5.1.9.
   [16 Sep 2009 13:42]
   Tony Bedford        
  An entry was added to the 5.1.9 changelog: When using the ON DUPLICATE KEY UPDATE functionality together with the rewriteBatchedStatements option set to true, an exception was generated when trying to execute the prepared statement: INSERT INTO config_table (modified,id_) VALUES (?,?) ON DUPLICATE KEY UPDATE modified=? The exception generated was: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2). at com.sag.etl.job.processors.JdbcInsertProcessor.flush(JdbcInsertProcessor.java:135) ...... Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2). at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926) at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3657) at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3641) at com.mysql.jdbc.PreparedStatement.setBytesNoEscapeNoQuotes(PreparedStatement.java:3391) at com.mysql.jdbc.PreparedStatement.setOneBatchedParameterSet(PreparedStatement.java:4203) at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1759) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1441) at com.sag.etl.job.processors.JdbcInsertProcessor.flush(JdbcInsertProcessor.java:131) ... 16 more


Description: I am using the ON DUPLICATE KEY UPDATE functionality together with the option of rewriteBatchedStatements set to true. when I try to execute the prepared statement I get the following exception: the prepared statement looks like this: insert into config_table (modified,id_) values (?,?) ON DUPLICATE KEY UPDATE modified=? java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2). at com.sag.etl.job.processors.JdbcInsertProcessor.flush(JdbcInsertProcessor.java:135) ...... Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2). at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926) at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3657) at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3641) at com.mysql.jdbc.PreparedStatement.setBytesNoEscapeNoQuotes(PreparedStatement.java:3391) at com.mysql.jdbc.PreparedStatement.setOneBatchedParameterSet(PreparedStatement.java:4203) at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1759) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1441) at com.sag.etl.job.processors.JdbcInsertProcessor.flush(JdbcInsertProcessor.java:131) ... 16 more problem does not appear if I use the 5.1.7 connector or any connector which is older. this seems like a newly introduced bug. How to repeat: create a table having a primary key id, and some value e.g. name. thePreparedStmt = theConnection.prepareStatement("insert into config_table (modified,id_) values (?,?) ON DUPLICATE KEY UPDATE modified=?"); thePreparedStmt.setString(1, "theID"); thePreparedStmt.setString(2, "Hello_world_"); thePreparedStmt.setString(3, "Hello_world_"); when you create the connection set the properties: Properties myProperties = new Properties(); myProperties.put("user", theUser); myProperties.put("password", thePassword); myProperties.put("cacheServerConfiguration", "true"); myProperties.put("useLocalSessionState", "true"); myProperties.put("elideSetAutoCommits", "true"); myProperties.put("alwaysSendSetIsolation", "true"); myProperties.put("rewriteBatchedStatements", "true"); myProperties.put("cachePrepStmts", "true"); myProperties.put("prepStmtCacheSize", "512"); myProperties.put("maintainTimeStats", "false"); myProperties.put("cacheResultSetMetadata", "true"); myProperties.put("maintainTimeStats", "false"); myProperties.put("cacheResultSetMetadata", "true"); myProperties.put("useUnbufferedIO", "false"); myProperties.put("useReadAheadInput", "false"); execute the insert statement: thePreparedStmt.executeBatch(); you will get the above exception. please elt me know if you need more details on reproducing it Suggested fix: check how you rewrite the statement, I guess you rewrite it up where the ON DUPLICATE KEY UPDATE part of the statement begins.... I have no better suggestion