Description:
The following code:
Connection c = ...
try {
PreparedStatement st = c.prepareStatement("create table test_table (id bigint not null, primary key (id))");
st.execute();
st.close();
} catch (SQLException t) {
throw new RuntimeException(t);
}
try {
PreparedStatement st = c.prepareStatement("insert into test_table (id) values (?)");
st.setInt(1, 1);
st.executeUpdate();
st.close();
} catch (SQLException t) {
throw new RuntimeException(t);
}
try {
PreparedStatement st = c.prepareStatement("select max(id) from test_table");
st.setFetchSize(1);
st.execute();
st.close();
} catch (SQLException t) {
throw new RuntimeException(t);
}
try {
PreparedStatement st = c.prepareStatement("select max(id) from test_table");
st.setFetchSize(0);
st.execute(); // <-- this throws java.lang.ArrayIndexOutOfBoundsException
st.close();
} catch (SQLException t) {
throw new RuntimeException(t);
}
Fails in the last st.execute() statement with exception:
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at com.mysql.cj.protocol.a.NativePacketPayload.readBytes(NativePacketPayload.java:563)
at com.mysql.cj.protocol.a.BinaryRowFactory.extractNativeEncodedColumn(BinaryRowFactory.java:150)
at com.mysql.cj.protocol.a.BinaryRowFactory.unpackBinaryResultSetRow(BinaryRowFactory.java:115)
at com.mysql.cj.protocol.a.BinaryRowFactory.createFromMessage(BinaryRowFactory.java:75)
at com.mysql.cj.protocol.a.BinaryRowFactory.createFromMessage(BinaryRowFactory.java:51)
at com.mysql.cj.protocol.a.ResultsetRowReader.read(ResultsetRowReader.java:87)
at com.mysql.cj.protocol.a.ResultsetRowReader.read(ResultsetRowReader.java:42)
at com.mysql.cj.protocol.a.NativeProtocol.read(NativeProtocol.java:1570)
at com.mysql.cj.protocol.a.BinaryResultsetReader.read(BinaryResultsetReader.java:92)
at com.mysql.cj.protocol.a.BinaryResultsetReader.read(BinaryResultsetReader.java:50)
at com.mysql.cj.protocol.a.NativeProtocol.read(NativeProtocol.java:1583)
at com.mysql.cj.protocol.a.NativeProtocol.readAllResults(NativeProtocol.java:1637)
at com.mysql.cj.ServerPreparedQuery.readExecuteResult(ServerPreparedQuery.java:433)
at com.mysql.cj.ServerPreparedQuery.serverExecute(ServerPreparedQuery.java:211)
at com.mysql.cj.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:632)
at com.mysql.cj.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:418)
... 40 more
The problem reproduces with useCursorFetch=true and cachePrepStmts=true connection properties.
How to repeat:
Create a connection with useCursorFetch=true and cachePrepStmts=true and run some prepared statement with setFetchSize(1), then create another prepared statement for the same query and try to run it with setFetchSize(0). Observe ArrayIndexOutOfBoundsException.
According to Javadoc setFetchSize(0) disables fetch size hint, so one would expect that this call is always safe, but apparently this is not true.
Tested with MySQL Connector/J 8.0.26 & MySQL 8.0.23