[CONJ-1124] OutOfMemoryError when executeUpdate Created: 2023-11-18  Updated: 2023-11-24  Resolved: 2023-11-24

Status: Closed
Project: MariaDB Connector/J
Component/s: Other
Affects Version/s: 3.3.0
Fix Version/s: 3.3.1

Type: Bug Priority: Critical
Reporter: Wenqian Deng Assignee: Diego Dupin
Resolution: Fixed Votes: 0
Labels: None
Environment:

MacOS



 Description   

The issue occurs when executing a JDBC test case using the MariaDB connector, leading to a java.lang.OutOfMemoryError: Java heap space error.
The same test case does not produce this error when using a MySQL connector, suggesting the issue might be a potential bug in the MariaDB connector.

@Test
public void test1() throws SQLException {
    Connection con;
    Statement stmt;
 
    con = DriverManager.getConnection("jdbc:mariadb://localhost:3366/test1290?user=user&password=password");
    stmt = con.createStatement(1003, 1008, 2);
    stmt.addBatch("CREATE TABLE table1290_0(id BIGINT PRIMARY KEY,value VARCHAR(100));");
    stmt.executeBatch();
    stmt.close();
 
    stmt = con.prepareStatement("SELECT id FROM table1290_0 WHERE id >= ?", 1005, 1007, 2);
    stmt.setFetchSize(1604040913);
 
    ((PreparedStatement) stmt).setObject(1, "id");
    ((PreparedStatement) stmt).addBatch();
    try {
        ((PreparedStatement) stmt).executeUpdate(); // java.lang.OutOfMemoryError: Java heap space
    } catch (Exception e) {
        System.out.println(e);
    }
}

stack trace:
java.lang.OutOfMemoryError: Java heap space

at org.mariadb.jdbc.client.result.StreamingResult.<init>(StreamingResult.java:90)
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:290)
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:886)
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:825)
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:744)
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:668)
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:336)
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:313)
at org.example.MySQL.test1(MySQL.java:36)



 Comments   
Comment by Wenqian Deng [ 2023-11-18 ]

Another interesting behavior I found is that if I catch the OutOfMemoryError and execute setTransactionIsolation after it, I get an ArrayIndexOutOfBoundsException

// .... the test case
try {
      ((PreparedStatement) stmt).executeUpdate(); // java.lang.OutOfMemoryError: Java heap space
} catch (OutOfMemoryError e) {
       System.out.println(e);
}
// add more commands
try {
      con.setTransactionIsolation(2);
} catch (Exception e) {
      System.out.println(e); // java.lang.ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 7
}

Comment by Diego Dupin [ 2023-11-22 ]

This can happen in 2 different places actually:
when running a Statement.execute*() /PrepareStatement.execute*() query after setting a huge fetch size, or using Resultset.setFetchSize

The connector creates an array of specified size. When the size is abnormally huge, the JVM will then throw an exception (the exchanges with the server are then in a completely wrong state and another command will generate an unexpected error). The only way to fix this is to limit the recovery buffer size. This buffer size should normally be small, since the objective is to avoid loading all results into memory.

Generated at Thu Feb 08 03:20:48 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.