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);
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.052 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
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()); } }