[CONJ-31] Data loss when using PreparedStatement.setCharacterStream and PreparedStatement.setClob Created: 2013-03-21  Updated: 2013-03-27  Resolved: 2013-03-27

Status: Closed
Project: MariaDB Connector/J
Component/s: None
Affects Version/s: 1.1.0, 1.1.1, 1.1.2
Fix Version/s: 1.1.2

Type: Bug Priority: Major
Reporter: Rune Bremnes Assignee: Vladislav Vaintroub
Resolution: Fixed Votes: 0
Labels: None

Attachments: File mariadb-java-client-multibyte-characters.patch    

 Description   

setCharacterStream and setClob (when a characterStream is used) uses the wrong length of the byte buffer sent to the server. It uses the character length and not the byte length. This will lead to lost characters in the database if multibyte characters are used.

I have attached a patch with a fix for the problem. The patch also includes some new test cases to show the problem.



 Comments   
Comment by Vladislav Vaintroub [ 2013-03-21 ]

Thanks. It would be great to have a little more explanation of the idea the patch. It changes many lines, and I can't tell from brief looking which ones are fixing the problem, and which ones are unrelated . Would it be possible? Thanks!

Comment by Rune Bremnes [ 2013-03-21 ]

No problem.

In ParameterWriter.write(OutputStream out, java.io.Reader reader, long length, boolean noBackslashEscapes)
The value returned from reader.read is the number of read characters not bytes. This value was used as input to writeBytesEscaped which expects the length in bytes.

Changed this to use the returned length in new String instead and using the length of the returned byte array as input to the writeBytesEscaped method. This should fix the setCharacterStream issue.

For the setClob issue, MySQLPreparedStatement.setClob used:
setParameter(parameterIndex,
new StreamParameter(x.getAsciiStream(), ((MySQLBlob)x).length(), connection.noBackslashEscapes));

The length returned here is the length from MySQLClob.length() and not MySQLBlob.length (it doesn't help to cast to MySQLBlob) which again is the number of characters and not bytes. Fixed this by just removing the length parameter.
The change to MySQLBlob.getBinaryStream is to get a stream of the correct length and not padded to 1024 bytes.

The rest is just removing an unnecessary IOException and added test cases. And updated the ersion of surefire to allow running single tests like:
mvn test -Dtest=DriverTest#testClob3

I hope this explains the changes.

Comment by Vladislav Vaintroub [ 2013-03-21 ]

Great explanations. Thanks a lot!

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