提交 376d098c authored 作者: Thomas Mueller's avatar Thomas Mueller

Server mode: CLOB and BLOB processing did not always work

上级 26f915bd
......@@ -21,6 +21,10 @@ Change Log
<h2>Next Version (unreleased)</h2>
<ul>
<li>Server mode: CLOB processing for texts larger than about 1 MB sometimes did not work.
</li>
<li>Server mode: BLOB processing for binaries larger than 2 GB did not work.
</li>
<li>Multi-threaded processing: concurrent deleting the same row could throw the exception
"Row not found when trying to delete".
</li>
......
......@@ -165,6 +165,9 @@ public class DataReader extends Reader {
@Override
public int read(char[] buff, int off, int len) throws IOException {
if (len == 0) {
return 0;
}
int i = 0;
try {
for (; i < len; i++) {
......@@ -172,6 +175,9 @@ public class DataReader extends Reader {
}
return len;
} catch (EOFException e) {
if (i == 0) {
return -1;
}
return i;
}
}
......
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.store;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* An filter input stream that limits the number of bytes that can be read.
*/
public class LimitInputStream extends FilterInputStream {
private long remaining;
public LimitInputStream(InputStream in, long maxLength) {
super(in);
this.remaining = maxLength;
}
@Override
public int available() throws IOException {
return (int) Math.min(remaining, in.available());
}
@Override
public boolean markSupported() {
return false;
}
@Override
public int read() throws IOException {
if (remaining == 0) {
return -1;
}
int result = in.read();
if (result >= 0) {
remaining--;
}
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (remaining == 0) {
return -1;
}
len = (int) Math.min(len, remaining);
int result = in.read(b, off, len);
if (result >= 0) {
remaining -= result;
}
return result;
}
}
......@@ -153,6 +153,9 @@ public class LobStorageMap implements LobStorageInterface {
b.reset();
in = b;
}
if (maxLength != Long.MAX_VALUE) {
in = new LimitInputStream(in, maxLength);
}
return createLob(in, type);
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED, e);
......
......@@ -72,10 +72,10 @@ class LobStorageRemoteInputStream extends InputStream {
} catch (DbException e) {
throw DbException.convertToIOException(e);
}
remainingBytes -= length;
if (length == 0) {
return -1;
}
remainingBytes -= length;
pos += length;
return length;
}
......
......@@ -462,6 +462,10 @@ 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);
......@@ -604,15 +608,6 @@ public class Transfer {
return ValueLobDb.create(
Value.BLOB, session.getDataHandler(), tableId, id, hmac, precision);
}
int len = (int) length;
byte[] small = new byte[len];
IOUtils.readFully(in, small, len);
int magic = readInt();
if (magic != LOB_MAGIC) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
}
return ValueLobDb.createSmallLob(Value.BLOB, small, length);
}
Value v = session.getDataHandler().getLobStorage().createBlob(in, length);
int magic = readInt();
......@@ -638,6 +633,10 @@ public class Transfer {
return ValueLobDb.create(
Value.CLOB, session.getDataHandler(), tableId, id, hmac, precision);
}
if (length < 0 || length > Integer.MAX_VALUE) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length="+ length);
}
DataReader reader = new DataReader(in);
int len = (int) length;
char[] buff = new char[len];
......
......@@ -102,6 +102,9 @@ public class ValueLobDb extends Value implements Value.ValueClob,
if (len == 0) {
break;
}
byte[] data = new String(buff, 0, len).getBytes("UTF-8");
out.write(data);
tmpPrecision += len;
}
} finally {
out.close();
......
......@@ -448,6 +448,21 @@ public abstract class TestBase {
*/
protected void fail(String string) {
lastPrint = 0;
if (string.length() > 100) {
// avoid long strings with special characters, because they are slow
// to display in Eclipse
char[] data = string.toCharArray();
for (int i = 0; i < data.length; i++) {
char c = data[i];
if (c >= 128 || c < 32) {
data[i] = (char) ('a' + (c & 15));
string = null;
}
}
if (string == null) {
string = new String(data);
}
}
println(string);
throw new AssertionError(string);
}
......@@ -744,6 +759,9 @@ public abstract class TestBase {
String s = expected.substring(0, i);
if (!actual.startsWith(s)) {
expected = expected.substring(0, i) + "<*>" + expected.substring(i);
if (al > 20) {
expected = "@" + i + " " + expected;
}
break;
}
}
......
......@@ -84,6 +84,7 @@ public class TestLob extends TestBase {
if (config.memory) {
return;
}
testLargeClob();
testLobCleanupSessionTemporaries();
testLobUpdateMany();
testLobVariable();
......@@ -108,6 +109,27 @@ public class TestLob extends TestBase {
deleteDb("lob");
}
private void testLargeClob() throws Exception {
deleteDb("lob");
Connection conn;
conn = reconnect(null);
conn.createStatement().execute(
"CREATE TABLE TEST(ID IDENTITY, C CLOB)");
PreparedStatement prep = conn.prepareStatement(
"INSERT INTO TEST(C) VALUES(?)");
int len = SysProperties.LOB_CLIENT_MAX_SIZE_MEMORY + 1;
prep.setCharacterStream(1, getRandomReader(len, 2), -1);
prep.execute();
conn = reconnect(conn);
ResultSet rs = conn.createStatement().executeQuery(
"SELECT * FROM TEST ORDER BY ID");
rs.next();
assertEqualReaders(getRandomReader(len, 2),
rs.getCharacterStream("C"), -1);
assertFalse(rs.next());
conn.close();
}
private void testRemovedAfterTimeout() throws Exception {
deleteDb("lob");
final String url = getURL("lob;lob_timeout=50", true);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论