提交 5b9781f6 authored 作者: noelgrandin's avatar noelgrandin

Fix an issue with storing Unicode surrogate pairs in CLOB columns.

上级 5ed6d648
...@@ -46,6 +46,7 @@ Change Log ...@@ -46,6 +46,7 @@ Change Log
</li><li>Issue 532: Javadoc for ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED looks wrong </li><li>Issue 532: Javadoc for ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED looks wrong
</li><li>Issue 528: Add Oracle-compatible TO_CHAR function, patch by Daniel Gredler. </li><li>Issue 528: Add Oracle-compatible TO_CHAR function, patch by Daniel Gredler.
</li><li>Issue 534: CREATE ALIAS NOCACHE, Patch by Nicolas Fortin </li><li>Issue 534: CREATE ALIAS NOCACHE, Patch by Nicolas Fortin
</li><li>Fix an issue with storing Unicode surrogate pairs in CLOB columns.
</li></ul> </li></ul>
<h2>Version 1.3.174 (2013-10-19)</h2> <h2>Version 1.3.174 (2013-10-19)</h2>
......
...@@ -10,10 +10,10 @@ import java.io.BufferedInputStream; ...@@ -10,10 +10,10 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -392,7 +392,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo ...@@ -392,7 +392,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
@Override @Override
public Reader getReader() { public Reader getReader() {
return IOUtils.getBufferedReader(getInputStream()); return new InputStreamReader(getInputStream(), Constants.UTF8);
} }
@Override @Override
......
...@@ -113,6 +113,7 @@ public class TestLob extends TestBase { ...@@ -113,6 +113,7 @@ public class TestLob extends TestBase {
testLob(false); testLob(false);
testLob(true); testLob(true);
testJavaObject(); testJavaObject();
testClobWithRandomUnicodeChars();
deleteDb("lob"); deleteDb("lob");
FileUtils.deleteRecursive(TEMP_DIR, true); FileUtils.deleteRecursive(TEMP_DIR, true);
} }
...@@ -1508,4 +1509,59 @@ public class TestLob extends TestBase { ...@@ -1508,4 +1509,59 @@ public class TestLob extends TestBase {
conn.close(); conn.close();
} }
private void testClobWithRandomUnicodeChars() throws Exception {
// This tests an issue we had with storing unicode surrogate pairs, which only
// manifested at the boundaries between blocks i.e. at 4k boundaries
deleteDb("lob");
Connection conn = getConnection("lob");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE logs(id int primary key auto_increment, message CLOB)");
PreparedStatement s1 = conn.prepareStatement("INSERT INTO logs (id, message) VALUES(null, ?)");
final Random rand = new Random();
for (int i = 1; i <= 100; i++) {
String data = randomUnicodeString(rand);
s1.setString(1, data);
s1.executeUpdate();
ResultSet rs = stat.executeQuery("SELECT id, message FROM logs ORDER BY id DESC LIMIT 1");
rs.next();
String read = rs.getString(2);
assertEquals(read, data);
}
conn.close();
}
private static String randomUnicodeString(Random rand) {
int count = 10000;
final char[] buffer = new char[count];
while (count-- != 0) {
char ch = (char) rand.nextInt();
if (ch >= 56320 && ch <= 57343) {
if (count == 0) {
count++;
} else {
// low surrogate, insert high surrogate after putting it
// in
buffer[count] = ch;
count--;
buffer[count] = (char) (55296 + rand.nextInt(128));
}
} else if (ch >= 55296 && ch <= 56191) {
if (count == 0) {
count++;
} else {
// high surrogate, insert low surrogate before putting
// it in
buffer[count] = (char) (56320 + rand.nextInt(128));
count--;
buffer[count] = ch;
}
} else if (ch >= 56192 && ch <= 56319) {
// private high surrogate, no effing clue, so skip it
count++;
} else {
buffer[count] = ch;
}
}
return new String(buffer);
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论