Your comment was added to the bug successfully.
| Bug #97824 | NullPointerException in NativeProtocol | ||
|---|---|---|---|
| Submitted: | 28 Nov 2019 7:42 | Modified: | 31 Aug 2020 22:29 |
| Reporter: | Roman Leventov | Email Updates: | |
| Status: | No Feedback | Impact on me: | |
| Category: | Connector / J | Severity: | S3 (Non-critical) |
| Version: | 8.0.18 | OS: | MacOS |
| Assigned to: | CPU Architecture: | Any | |
[31 Jul 2020 22:29]
Filipe Silva
Hi Roman, Thank you for this bug report and your interest in Connector/J. I'm sorry for the late reply, but can you provide a full stack trace with the exception, please? Thanks,
[1 Sep 2020 1:00]
Bugs System
No feedback was provided for this bug for over a month, so it is being suspended automatically. If you are able to provide the information that was originally requested, please do so and change the status of the bug back to "Open".
[3 Sep 2020 5:37]
Marcle leo
Hi Filipe,
I had the same problem recently, and I have a reproducible test case here.
How to repeat:
import java.lang.reflect.Method;
import java.sql.*;
public class Demo {
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// Set your connection parameters
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false" +
"&allowPublicKeyRetrieval=true&serverTimezone=UTC","root","12345678");
// Set the breakpoint here or sleep the thread
// Next, close the MySQL service and continue.
Thread.sleep(30 * 1000);
Method pingInternal = conn.getClass().getMethod("pingInternal", boolean.class, int.class);
pingInternal.invoke(conn, true, 1000);
} catch (Exception e) {
//
e.printStackTrace();
} finally {
try{
if(statement!=null) statement.close();
}catch(SQLException se2){
}
try{
if(conn!=null) conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
}
}
Description:
My guess is that when the MySQL service was first shut down, the server-side TCP connection was in the FIN_WAIT_2/FIN_WAIT_2 state and could accept requests but not return data, so the following code is executing normally.
(The following code is taken from NativeProtocol#sendCommand.)
try {
clearInputStream();
this.packetSequence = -1;
send(queryPacket, queryPacket.getPosition());
} catch (CJException ex) {
// don't wrap CJExceptions
throw ex;
} catch (Exception ex) {
throw ExceptionFactory.createCommunicationsException(this.propertySet, this.serverSession, this.getPacketSentTimeHolder(),
this.getPacketReceivedTimeHolder(), ex, getExceptionInterceptor());
}
But this part of the code has an internal exception and sets the current this.socketConnection.getMysqlSocket() to null.
(The following code is taken from NativeProtocol#sendCommand.)
if (!skipCheck) {
if ((COMMAND == NativeConstants.COM_STMT_EXECUTE) || (COMMAND == NativeConstants.COM_STMT_RESET)) {
this.packetReader.resetMessageSequence();
}
returnPacket = checkErrorMessage(command);
if (this.queryInterceptors ! = null) {
returnPacket = (NativePacketPayload) invokeQueryInterceptorsPost(queryPacket, returnPacket, false);
}
}
When executing to the finally statement block, when satisfying timeoutMillis ! = 0 condition, the following code throws the NPE.
(The following code is taken from NativeProtocol#sendCommand.)
this.socketConnection.getMysqlSocket().setSoTimeout(oldTimeout);

Description: There may be a NullPointerException in NativeProtocol.java in line 661: } finally { if (timeoutMillis != 0) { try { this.socketConnection.getMysqlSocket().setSoTimeout(oldTimeout); // <- this line } catch (IOException e) { throw ExceptionFactory.createCommunicationsException(this.propertySet, this.serverSession, this.getPacketSentTimeHolder(), this.getPacketReceivedTimeHolder(), e, getExceptionInterceptor()); } } } this.socketConnection.getMysqlSocket() may return null. How to repeat: private static Network network; private static MySQLContainer mysql; private static int mysqlPort; private static ToxiproxyContainer toxiproxy; private static ToxiproxyContainer.ContainerProxy proxy; private static String jdbcUrl; @BeforeClass public static void setupContainers() { network = Network.newNetwork(); mysql = (MySQLContainer) new MySQLContainer("mysql:5.7").withNetwork(network); mysql.start(); mysqlPort = mysql.getMappedPort(MySQLContainer.MYSQL_PORT); toxiproxy = new ToxiproxyContainer().withNetwork(network); toxiproxy.start(); proxy = toxiproxy.getProxy(mysql, MySQLContainer.MYSQL_PORT); jdbcUrl = "jdbc:mysql://" + proxy.getContainerIpAddress() + ":" + proxy.getProxyPort() + "/" + mysql.getDatabaseName(); } @AfterClass public static void shutdownContainers() { //noinspection EmptyTryBlock: let try-with-resources do the work try (final Network ignore1 = network; final MySQLContainer ignore2 = mysql; final ToxiproxyContainer ignore3 = toxiproxy) { } } @Test public void testHikariDbDisconnected() throws SQLException { HikariConfig config = new HikariConfig(); config.setJdbcUrl(jdbcUrl); config.setUsername(mysql.getUsername()); config.setPassword(mysql.getPassword()); try (HikariDataSource ds = new HikariDataSource(config)) { proxy.setConnectionCut(true); // Emulate db disconnection System.out.println(ds.getConnection().prepareCall("SELECT 1;").execute()); } }