Bug #96900 statement.cancel()create a database connection but does not close the connection
Submitted: 17 Sep 2019 8:43 Modified: 11 Dec 2021 16:27
Reporter: beitian wang Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:Versions 8.0.13-8.0.17 OS:Any
Assigned to: CPU Architecture:Any

[17 Sep 2019 8:43] beitian wang
Description:
statement.cancel(),In this method, one thread interrupts another thread that is executing and interrupts by creating a database connection, but the connection is not closed.

How to repeat:
@Test
    public void testInterupt() throws  Exception{
        Map<String,Object> map = new HashMap<>();
        map.put("ip","XXXXX");
        map.put("port","3306");
        map.put("readUserName","XXXX");
        map.put("readUserPassword","XXXXX");
        map.put("dbType",1);
        //连接 目标数据库,批量执行sql
        DBUtil2 db = new DBUtil2("webdb",map,null);
        String sql2 ="SELECT SLEEP(60)";
       Connection conn = db.getConnection(db);
        PreparedStatement statement = conn.prepareStatement(sql2);

        new Thread(()->{
            try {
                System.out.println("begin -----------------------.");
               statement.executeQuery(sql2);
            }catch (Exception e){
                System.err.println("查询报错啦");
                System.out.println("close11111111111 .....");
                e.printStackTrace();
            }

        }).start();

        Thread.sleep(2000);

        new Thread(()->{
            try {
                statement.cancel();
                System.out.println("close22222222222222222 .....");
                conn.close();
            }catch (Exception e){
                System.err.println("报错啦");
            }

        }).start();

        Thread.sleep(60 * 1000 +100);

    }

Suggested fix:
After executing the newSession.sendCommand() method, the newSession.forceClose () is finally called.
[26 Sep 2019 12:58] MySQL Verification Team
Hello Beitian,

Thank you for the report.

regards,
Umesh
[15 Apr 2020 2:22] beitian wang
Add the method "newSession.getProtocol().getSocketConnection().forceClose()" in finally{} of StatementImpl.cancel()
[15 Apr 2020 2:22] beitian wang
Add the method "newSession.getProtocol().getSocketConnection().forceClose()" in finally{} of StatementImpl.cancel()
[19 May 2021 0:50] Charly Batista
The issue is that the two objects that are created to, theoretically, run the KILL command on MySQL are never used:
```        if (!this.isClosed && this.connection != null) {
            JdbcConnection cancelConn = null;
            java.sql.Statement cancelStmt = null;
<...>
            } finally {
                if (cancelStmt != null) {
                    cancelStmt.close();
                }

                if (cancelConn != null) {
                    cancelConn.close();
                }
            }
```

But the object that is used is a "NativeSession" one:
```
                NativeSession newSession = new NativeSession(this.session.getHostInfo(), this.session.getPropertySet());
                newSession.connect(hostInfo, user, password, database, 30000, new TransactionEventHandler() {
                    @Override
                    public void transactionCompleted() {
                    }

                    @Override
                    public void transactionBegun() {
                    }
                });
                newSession.sendCommand(new NativeMessageBuilder().buildComQuery(newSession.getSharedSendPacket(), "KILL QUERY " + this.session.getThreadId()),
                        false, 0);
                setCancelStatus(CancelStatus.CANCELED_BY_USER);
```

It should either use the "JdbcConnection" and "Statement" objects or remove them and do the correct test and cleanup on the finally section.

---
Charly
[11 Dec 2021 16:27] Daniel So
Posted by developer:
 
Added the following entry to the Connector/J 8.0.28 changelog: 

"A new session created for executing Statement.cancel() remained open after the Statement had been cancelled. With this fix, the session is closed after the Statement cancellation."