Bug #108500 updateBlob fails with ClassCastException when replication is in use
Submitted: 15 Sep 2022 20:03 Modified: 16 Sep 2022 10:31
Reporter: Stephen Baker Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:8.0.30 OS:Any
Assigned to: CPU Architecture:x86

[15 Sep 2022 20:03] Stephen Baker
Description:
When :replication is included in the connection string then ResultSet.updateBlob fails with a ClassCastException like the following:

```
Exception in thread "main" java.lang.ClassCastException: class com.sun.proxy.$Proxy3 cannot be cast to class com.mysql.cj.jdbc.ClientPreparedStatement (com.sun.proxy.$Proxy3 and com.mysql.cj.jdbc.ClientPreparedStatement are in unnamed module of loader 'app')
	at com.mysql.cj.jdbc.result.UpdatableResultSet.syncUpdate(UpdatableResultSet.java:1130)
	at com.mysql.cj.jdbc.result.UpdatableResultSet.updateBlob(UpdatableResultSet.java:1270)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at com.mysql.cj.jdbc.ha.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:107)
	at com.sun.proxy.$Proxy5.updateBlob(Unknown Source)
	at com.raveu.test.Test.writeToFile(Test.java:29)
	at com.raveu.test.Test.main(Test.java:42)
```

Running through the error in the debugger I have traced the problem to:
```
MultiHostMySQLConnection.clientPrepareStatement(String)
```

Notably without :replication: in the connection string ConnectionImpl is used directly and there is no error.

I found this in Apache ArtemisMQ and was able to reproduce with an example program below

How to repeat:
Create a table in a database in mysql:

```
CREATE TABLE `blob_test` (
  `id` bigint NOT NULL,
  `data` longblob,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
```

Then run the following test program (adjust the connection string for your database):
```
package com.raveu.test;

import java.sql.*;

public class Test {
    public void writeToFile() throws SQLException {
        byte data[] = {(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef};
        Connection connection = DriverManager.getConnection("jdbc:mysql:replication://localhost,localhost/DbRave?user=rave&password=rave");
        connection.setAutoCommit(false);
        try (PreparedStatement appendToLargeObject = connection.prepareStatement(
                "SELECT id, data FROM blob_test WHERE id=? FOR UPDATE",
                ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_UPDATABLE)) {
            appendToLargeObject.setLong(1, 1L);

            try (ResultSet rs = appendToLargeObject.executeQuery()) {
                if (rs.next()) {
                    Blob blob = rs.getBlob(1);
                    if (blob == null) {
                        blob = connection.createBlob();
                    }
                    blob.truncate(0);
                    blob.setBytes(1, data);
                    rs.updateBlob(1, blob);
                    rs.updateRow();
                }
                connection.commit();
            } catch (SQLException e) {
                connection.rollback();
                throw e;
            }
        }
    }

    public static void main(String args[]) throws Exception {
        var t = new Test();
        t.writeToFile();
    }
}
```
[15 Sep 2022 20:14] Stephen Baker
Column indexes should be 2 not 1 above.
[15 Sep 2022 20:56] Stephen Baker
This issue appears to be closely related to https://bugs.mysql.com/bug.php?id=95210 - I expect the same fix would work here.
[16 Sep 2022 10:31] MySQL Verification Team
Hello Stephen,

Thank you for the report test case.
Verified as described.

regards,
Umesh