Bug #101558 NullPointerException when executing invalid query with useUsageAdvisor enabled
Submitted: 11 Nov 2020 9:23 Modified: 12 Mar 2021 16:40
Reporter: Andrey Tarashevskiy Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:8.0.22 OS:Any
Assigned to: CPU Architecture:Any

[11 Nov 2020 9:23] Andrey Tarashevskiy
Description:
Hello, 
we faced an java.lang.NullPointerException (see the whole trace below) when trying to execute statement which can't be used as ServerPreparedStatement (I'll file another bug for that case too) with useUsageAdvisor=true connection property.

Root cause in that when execution of `serverPrepare(sql)` (ServerPreparedStatement.java:134) fails with `42000 Error` from server `ClientPreparedStatement.realClose()` function will be executed.

As the query wasn't yet prepared the PreparedQuery.getQueryBindings() will return null and throw NPE in ClientPreparedStatement.java:1304 if useUsageAdvisor is enabled.

How to repeat:
1. Connect to MySQL Server with `cachePrepStmts=true&useServerPrepStmts=true&useUsageAdvisor=true` in the url
2. Execute any unpreparable statement like 'SELECT 1 FROM DUAL; SELECT 1 FROM DUAL`

Suggested fix:
There should be check that value returned by getQueryBindings() is no null
[11 Nov 2020 9:30] Andrey Tarashevskiy
Sorry, I forgot to attach stacktrace:
```
java.lang.NullPointerException
at com.mysql.cj.jdbc.ClientPreparedStatement.realClose(ClientPreparedStatement.java:1304)
at com.mysql.cj.jdbc.ServerPreparedStatement.realClose(ServerPreparedStatement.java:544)
at com.mysql.cj.jdbc.ServerPreparedStatement.<init>(ServerPreparedStatement.java:136)
at com.mysql.cj.jdbc.ServerPreparedStatement.getInstance(ServerPreparedStatement.java:103)
at com.mysql.cj.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:1625)
at com.mysql.cj.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:1583)
at com.mysql.cj.jdbc.ClientPreparedStatement.executePreparedBatchAsMultiStatement(ClientPreparedStatement.java:500)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchInternal(ClientPreparedStatement.java:431)
at com.mysql.cj.jdbc.StatementImpl.executeBatch(StatementImpl.java:796)
at com.zaxxer.hikari.pool.ProxyStatement.executeBatch(ProxyStatement.java:128)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeBatch(HikariProxyPreparedStatement.java)
at org.jetbrains.exposed.sql.statements.BatchUpdateStatement.executeInternal(BatchUpdateStatement.kt:43)
at org.jetbrains.exposed.sql.statements.BatchUpdateStatement.executeInternal(BatchUpdateStatement.kt:14)
at org.jetbrains.exposed.sql.statements.Statement.executeIn$exposed(Statement.kt:59)
at org.jetbrains.exposed.sql.Transaction.exec(Transaction.kt:183)
at org.jetbrains.exposed.sql.Transaction.exec(Transaction.kt:125)
at org.jetbrains.exposed.sql.statements.Statement.execute(Statement.kt:29)
at org.jetbrains.exposed.sql.statements.EntityBatchUpdate.execute(BatchUpdateStatement.kt:74)
at org.jetbrains.exposed.dao.EntityCache.flush(Entity.kt:420)
at org.jetbrains.exposed.dao.EntityCache.flush(Entity.kt:401)
at org.jetbrains.exposed.sql.Transaction.flushCache(Transaction.kt:85)
at org.jetbrains.exposed.sql.Transaction.commit(Transaction.kt:62)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt$inTopLevelTransaction$1.invoke(ThreadLocalTransactionManager.kt:157)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt$inTopLevelTransaction$2.invoke(ThreadLocalTransactionManager.kt:197)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.keepAndRestoreTransactionRefAfterRun(ThreadLocalTransactionManager.kt:205)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.inTopLevelTransaction(ThreadLocalTransactionManager.kt:196)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.inTopLevelTransaction$default(ThreadLocalTransactionManager.kt:142)
at jobs.recurrent.cleanup.EntityBatchProcessor.run(EntityBatchProcessor.kt:131)
at jobs.recurrent.cleanup.EntityBatchProcessor.run$default(EntityBatchProcessor.kt:114)
at jobs.recurrent.cleanup.OrdersCleanupJob.cancelOrdersWithFailedPayments(OrdersCleanupJob.kt:163)
at jobs.recurrent.cleanup.OrdersCleanupJob.access$cancelOrdersWithFailedPayments(OrdersCleanupJob.kt:15)
at jobs.recurrent.cleanup.OrdersCleanupJob$1$5.invoke(OrdersCleanupJob.kt:21)
at jobs.recurrent.cleanup.OrdersCleanupJob$1$5.invoke(OrdersCleanupJob.kt:15)
at jobs.recurrent.cleanup.OrdersCleanupJob$1.invoke(OrdersCleanupJob.kt:22)
at jobs.recurrent.cleanup.OrdersCleanupJob$1.invoke(OrdersCleanupJob.kt:15)
at jetprofile.jobs.RunnableJobDescriptor.run(JobsModel.kt:53)
at jobs.recurrent.cleanup.CleanupJobsRegistration$init$$inlined$registerRecurrentRunnableDescriptor$3.invoke(JobsModel.kt:93)
at jobs.recurrent.cleanup.CleanupJobsRegistration$init$$inlined$registerRecurrentRunnableDescriptor$3.invoke(JobsModel.kt:63)
at jetprofile.jobs.JobRunner$Companion$createRunnerFor$2.execute(JobsModel.kt:74)
at jetprofile.dispatcher.Dispatcher$execute$2$1$2.invoke(Dispatcher.kt:378)
at jetprofile.dispatcher.Dispatcher$execute$2$1$2.invoke(Dispatcher.kt:47)
at jetprofile.browseragent.NewRelicUtilsKt.traceInNewRelic(NewRelicUtils.kt:21)
at jetprofile.dispatcher.Dispatcher$execute$2$1.invoke(Dispatcher.kt:377)
at jetprofile.dispatcher.Dispatcher$execute$2$1.invoke(Dispatcher.kt:47)
at jetprofile.jobs.DefaultJobGate.tryDo(JobsModel.kt:159)
at jetprofile.dispatcher.Dispatcher$execute$2.invoke(Dispatcher.kt:363)
at jetprofile.dispatcher.Dispatcher$execute$2.invoke(Dispatcher.kt:47)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt$inTopLevelTransaction$1.invoke(ThreadLocalTransactionManager.kt:156)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt$inTopLevelTransaction$2.invoke(ThreadLocalTransactionManager.kt:197)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.keepAndRestoreTransactionRefAfterRun(ThreadLocalTransactionManager.kt:205)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.inTopLevelTransaction(ThreadLocalTransactionManager.kt:196)
at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.inTopLevelTransaction$default(ThreadLocalTransactionManager.kt:142)
at jetprofile.dispatcher.Dispatcher.execute(Dispatcher.kt:355)
at jetprofile.dispatcher.Dispatcher.access$execute(Dispatcher.kt:47)
at jetprofile.dispatcher.Dispatcher$extractJobs$f$1.run(Dispatcher.kt:311)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.jetbrains.intdev.utils.kotlin.thread.ExectorServiceKt$namedFactory$1$newThread$1.invoke(ExectorService.kt:26)
at org.jetbrains.intdev.utils.kotlin.thread.ExectorServiceKt$namedFactory$1$newThread$1.invoke(ExectorService.kt:23)
at kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)
```
[11 Nov 2020 10:11] MySQL Verification Team
Hello Andrey,

Thank you for the report.

regards,
Umesh
[12 Mar 2021 16:40] Daniel So
Posted by developer:
 
Added the following entry to the Connector/J 8.0.24 changelog: 

"A NullPointerException was returned when a statement that could not be used as a ServerPreparedStatement was executed and the connection property useUsageAdvisor was set to true. With this fix, a SQLException is returned instead."