Bug #62006 java.io.NotSerializableException: java.io.StringReader when profileSQL=true
Submitted: 27 Jul 2011 15:04 Modified: 6 Apr 2022 22:47
Reporter: Manuel Darveau Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:5.1.17 OS:Any
Assigned to: Alexander Soklakov CPU Architecture:Any

[27 Jul 2011 15:04] Manuel Darveau
Description:
If profileSQL=true and useServerPrepStmts=true on the driver connection string, the driver will throw a java.io.NotSerializableException: java.io.StringReader on insert statement.

My hibernate entity is annotated to @Lob which map to LONGTEXT in mysql.

The problem is in com.mysql.jdbc.PreparedStatement.setObject(int, Object). There should be another "else if":
...
} else if (parameterObj instanceof Reader) {
  setCharacterStream(parameterIndex, (Reader)parameterObj);
...

How to repeat:
- Set the profileSQL=true and useServerPrepStmts=true parameters on the driver.
- Create a table with LONGTEXT
- Prepare an insert statement
- Execute an insert statement passing a StringReader as the parameter

Suggested fix:
In com.mysql.jdbc.PreparedStatement.setObject(int, Object). There should be another "else if":
...
} else if (parameterObj instanceof Reader) {
  setCharacterStream(parameterIndex, (Reader)parameterObj);
...
[6 Aug 2011 11:11] Sveta Smirnova
Thank you for the report.

I can not repeat described behavior if use code following:

import testsuite.BaseTestCase;
import java.sql.*;
import java.io.StringReader;

public class bug62006 extends BaseTestCase {
	
	public bug62006(String name) {
		super(name);
	}

	public static void main(String[] args) {
		junit.textui.TestRunner.run(bug62006.class);
	}

	public void testbug62006() throws Exception {
		try {
			this.stmt.execute("drop table if exists testbug62006");
			this.stmt.execute("create table testbug62006(f1 longtext)");
			
			this.pstmt = this.conn.prepareStatement("insert into testbug62006 values(?)");
			this.pstmt.setObject(1, new StringReader("test"), java.sql.Types.LONGVARCHAR, 0);
			this.pstmt.execute();
}
}	
}

Please provide example of how you pass StringReader
[25 Aug 2011 19:55] Manuel Darveau
In your test, replace "this.pstmt.setObject(1, new StringReader("test"), java.sql.Types.LONGVARCHAR, 0);" by this.pstmt.setObject(1, new StringReader("test"));" and it will fail (assuming that you have the profileSQL=true in the parameters.
[1 Sep 2011 7:12] Tonci Grgin
I presume this has to do with http://dev.mysql.com/doc/refman/5.5/en/cj-news-5-1-17.html:
  There was a concurrency bottleneck in Java's character set encoding/decoding
when converting bytes to/from String values.ImportantNo longer use
String.getBytes(...), or new String(byte[]...).
Use the StringUtilsmethod instead.(Bug #61105)
[1 Sep 2011 21:15] Manuel Darveau
Hi Tonci.

I don't think this is related to the bug you mentionned.

There is simply a missing else in one method of the driver. Please look at the "Suggested fix" section of my bug report.
[2 Sep 2011 6:04] Tonci Grgin
Taking over.
[24 Apr 2013 11:01] Alexander Soklakov
Hi Manuel,

Verified by code review.
[6 Apr 2022 22:47] Daniel So
Posted by developer:
 
Added the following entry to the Connector/J 8.0.29 changelog: 

"When using server-side prepared statements and the connection property profileSQL was set to true, setting a parameter of type LONGTEXT using a StringReader() resulted in a java.io.NotSerializableException."