Bug #84163 NPE inside statement interceptor with rewriteBatchedStatements=true
Submitted: 12 Dec 2016 12:28 Modified: 19 Dec 2016 10:12
Reporter: Dmitry Adamian Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / J Severity:S3 (Non-critical)
Version:5.1.40 OS:Any
Assigned to: Filipe Silva CPU Architecture:Any

[12 Dec 2016 12:28] Dmitry Adamian
Description:
PreparedStatement.getPreparedSql() method throws NullPointerException when called inside StatementInterceptorV2.preProcess() if JDBC connection sets parameter rewriteBatchedStatements=true.

Exception stack trace:
Caused by: java.sql.SQLException: Unexpected exception encountered during query.
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2582)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073)
	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009)
	at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5098)
	at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1543)
	... 35 more
Caused by: java.lang.NullPointerException
	at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
	at com.mysql.jdbc.StringUtils.findCharset(StringUtils.java:124)
	at com.mysql.jdbc.StringUtils.toString(StringUtils.java:2199)
	at com.mysql.jdbc.PreparedStatement$ParseInfo.getSqlForBatch(PreparedStatement.java:484)
	at com.mysql.jdbc.PreparedStatement.getPreparedSql(PreparedStatement.java:5049)
	at example.Interceptor.preProcess(Interceptor.java:26)
	at com.mysql.jdbc.MysqlIO.invokeStatementInterceptorsPre(MysqlIO.java:2859)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2580)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2549)
	... 40 more

How to repeat:
1. Use rewriteBatchedStatements=true parameter in JDBC connection
2. Register statement interceptor with JDBC URL. Statement interceptor should call PreparedStatement.getPreparedSql()
3. Execute batch update using connection.prepareStatement(), statement.addBatch() and statement.executeBatch().

I've created a reproducible test as a Maven project (https://github.com/dmitry-at-genestack/mysql-jdbc-bug-report). Will also add it as an attachment.

Suggested fix:
Add a check for null charEncoding in method getSqlForBatch(ParseInfo batchInfo)
[12 Dec 2016 12:30] Dmitry Adamian
Maven project with test case for reproducing the bug

Attachment: connector-j-npe-bug-report.zip (application/zip, text), 5.12 KiB.

[14 Dec 2016 10:54] Filipe Silva
Hi Dmitry,

Thank you for this bug report. It is as you described.

As a workaround you can use server-side prepared statements (useServerPrepStmts=true) in which this seems not to be a problem.

Please let us know if this workaround works for you at the moment.

Thank you,
[19 Dec 2016 10:12] Dmitry Adamian
Using parameter useServerPrepStmts=true fixes this problem but negatively affects insert/update performance.

Actually this is not a major problem for me. I am using OpenZipkin/Brave (https://github.com/openzipkin/brave) for collecting performance tracing information. Exception is thrown from statement interceptor of this library. But I can just write custom statement interceptor using PreparedStatement.asSql() instead of PreparedStatement.getPreparedSql().