Unverified 提交 862d6154 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #871 from katzyn/clob2

Fix OOME in Transfer.readValue() with large CLOB V2
......@@ -171,7 +171,7 @@ public class DataReader extends Reader {
int i = 0;
try {
for (; i < len; i++) {
buff[i] = readChar();
buff[off + i] = readChar();
}
return len;
} catch (EOFException e) {
......
......@@ -14,7 +14,6 @@ import java.io.Reader;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
......@@ -463,10 +462,6 @@ public class Transfer {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length=" + length);
}
if (length > Integer.MAX_VALUE) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length="+ length);
}
writeLong(length);
Reader reader = v.getReader();
Data.copyString(reader, out);
......@@ -652,21 +647,10 @@ public class Transfer {
return ValueLobDb.create(
Value.CLOB, session.getDataHandler(), tableId, id, hmac, precision);
}
if (length < 0 || length > Integer.MAX_VALUE) {
if (length < 0) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length="+ length);
}
DataReader reader = new DataReader(in);
int len = (int) length;
char[] buff = new char[len];
IOUtils.readFully(reader, buff, len);
int magic = readInt();
if (magic != LOB_MAGIC) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
}
byte[] small = new String(buff).getBytes(StandardCharsets.UTF_8);
return ValueLobDb.createSmallLob(Value.CLOB, small, length);
}
Value v = session.getDataHandler().getLobStorage().
createClob(new DataReader(in), length);
......
......@@ -26,6 +26,7 @@ import org.h2.store.FileStoreInputStream;
import org.h2.store.FileStoreOutputStream;
import org.h2.store.LobStorageFrontend;
import org.h2.store.LobStorageInterface;
import org.h2.store.RangeReader;
import org.h2.store.fs.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
......@@ -544,6 +545,15 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/
public static ValueLobDb createTempClob(Reader in, long length,
DataHandler handler) {
if (length >= 0) {
// Otherwise BufferedReader may try to read more data than needed and that
// blocks the network level
try {
in = new RangeReader(in, 0, length);
} catch (IOException e) {
throw DbException.convert(e);
}
}
BufferedReader reader;
if (in instanceof BufferedReader) {
reader = (BufferedReader) in;
......
......@@ -119,7 +119,20 @@ public class TestLobApi extends TestBase {
prep.setString(1, "");
prep.setBytes(2, new byte[0]);
prep.execute();
Random r = new Random(1);
char[] charsSmall = new char[20];
for (int i = 0; i < charsSmall.length; i++) {
charsSmall[i] = (char) r.nextInt(10000);
}
String dSmall = new String(charsSmall);
prep.setCharacterStream(1, new StringReader(dSmall), -1);
byte[] bytesSmall = new byte[20];
r.nextBytes(bytesSmall);
prep.setBinaryStream(2, new ByteArrayInputStream(bytesSmall), -1);
prep.execute();
char[] chars = new char[100000];
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) r.nextInt(10000);
......@@ -130,6 +143,7 @@ public class TestLobApi extends TestBase {
r.nextBytes(bytes);
prep.setBinaryStream(2, new ByteArrayInputStream(bytes), -1);
prep.execute();
conn.setAutoCommit(false);
ResultSet rs = stat.executeQuery("select * from test order by id");
rs.next();
......@@ -138,18 +152,27 @@ public class TestLobApi extends TestBase {
rs.next();
Clob c2 = rs.getClob(2);
Blob b2 = rs.getBlob(3);
rs.next();
Clob c3 = rs.getClob(2);
Blob b3 = rs.getBlob(3);
assertFalse(rs.next());
// now close
rs.close();
// but the LOBs must stay open
assertEquals(0, c1.length());
assertEquals(0, b1.length());
assertEquals(chars.length, c2.length());
assertEquals(bytes.length, b2.length());
assertEquals("", c1.getSubString(1, 0));
assertEquals(new byte[0], b1.getBytes(1, 0));
assertEquals(d, c2.getSubString(1, (int) c2.length()));
assertEquals(bytes, b2.getBytes(1, (int) b2.length()));
assertEquals(charsSmall.length, c2.length());
assertEquals(bytesSmall.length, b2.length());
assertEquals(dSmall, c2.getSubString(1, (int) c2.length()));
assertEquals(bytesSmall, b2.getBytes(1, (int) b2.length()));
assertEquals(chars.length, c3.length());
assertEquals(bytes.length, b3.length());
assertEquals(d, c3.getSubString(1, (int) c3.length()));
assertEquals(bytes, b3.getBytes(1, (int) b3.length()));
stat.execute("drop table test");
conn.close();
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论