提交 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 ...@@ -21,6 +21,10 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <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 <li>Multi-threaded processing: concurrent deleting the same row could throw the exception
"Row not found when trying to delete". "Row not found when trying to delete".
</li> </li>
......
...@@ -165,6 +165,9 @@ public class DataReader extends Reader { ...@@ -165,6 +165,9 @@ public class DataReader extends Reader {
@Override @Override
public int read(char[] buff, int off, int len) throws IOException { public int read(char[] buff, int off, int len) throws IOException {
if (len == 0) {
return 0;
}
int i = 0; int i = 0;
try { try {
for (; i < len; i++) { for (; i < len; i++) {
...@@ -172,6 +175,9 @@ public class DataReader extends Reader { ...@@ -172,6 +175,9 @@ public class DataReader extends Reader {
} }
return len; return len;
} catch (EOFException e) { } catch (EOFException e) {
if (i == 0) {
return -1;
}
return i; 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 { ...@@ -153,6 +153,9 @@ public class LobStorageMap implements LobStorageInterface {
b.reset(); b.reset();
in = b; in = b;
} }
if (maxLength != Long.MAX_VALUE) {
in = new LimitInputStream(in, maxLength);
}
return createLob(in, type); return createLob(in, type);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED, e); throw DbException.get(ErrorCode.OBJECT_CLOSED, e);
......
...@@ -72,10 +72,10 @@ class LobStorageRemoteInputStream extends InputStream { ...@@ -72,10 +72,10 @@ class LobStorageRemoteInputStream extends InputStream {
} catch (DbException e) { } catch (DbException e) {
throw DbException.convertToIOException(e); throw DbException.convertToIOException(e);
} }
remainingBytes -= length;
if (length == 0) { if (length == 0) {
return -1; return -1;
} }
remainingBytes -= length;
pos += length; pos += length;
return length; return length;
} }
......
...@@ -462,6 +462,10 @@ public class Transfer { ...@@ -462,6 +462,10 @@ public class Transfer {
throw DbException.get( throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length=" + length); ErrorCode.CONNECTION_BROKEN_1, "length=" + length);
} }
if (length > Integer.MAX_VALUE) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length="+ length);
}
writeLong(length); writeLong(length);
Reader reader = v.getReader(); Reader reader = v.getReader();
Data.copyString(reader, out); Data.copyString(reader, out);
...@@ -604,15 +608,6 @@ public class Transfer { ...@@ -604,15 +608,6 @@ public class Transfer {
return ValueLobDb.create( return ValueLobDb.create(
Value.BLOB, session.getDataHandler(), tableId, id, hmac, precision); 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); Value v = session.getDataHandler().getLobStorage().createBlob(in, length);
int magic = readInt(); int magic = readInt();
...@@ -638,6 +633,10 @@ public class Transfer { ...@@ -638,6 +633,10 @@ public class Transfer {
return ValueLobDb.create( return ValueLobDb.create(
Value.CLOB, session.getDataHandler(), tableId, id, hmac, precision); 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); DataReader reader = new DataReader(in);
int len = (int) length; int len = (int) length;
char[] buff = new char[len]; char[] buff = new char[len];
......
...@@ -102,6 +102,9 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -102,6 +102,9 @@ public class ValueLobDb extends Value implements Value.ValueClob,
if (len == 0) { if (len == 0) {
break; break;
} }
byte[] data = new String(buff, 0, len).getBytes("UTF-8");
out.write(data);
tmpPrecision += len;
} }
} finally { } finally {
out.close(); out.close();
......
...@@ -448,6 +448,21 @@ public abstract class TestBase { ...@@ -448,6 +448,21 @@ public abstract class TestBase {
*/ */
protected void fail(String string) { protected void fail(String string) {
lastPrint = 0; 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); println(string);
throw new AssertionError(string); throw new AssertionError(string);
} }
...@@ -744,6 +759,9 @@ public abstract class TestBase { ...@@ -744,6 +759,9 @@ public abstract class TestBase {
String s = expected.substring(0, i); String s = expected.substring(0, i);
if (!actual.startsWith(s)) { if (!actual.startsWith(s)) {
expected = expected.substring(0, i) + "<*>" + expected.substring(i); expected = expected.substring(0, i) + "<*>" + expected.substring(i);
if (al > 20) {
expected = "@" + i + " " + expected;
}
break; break;
} }
} }
......
...@@ -84,6 +84,7 @@ public class TestLob extends TestBase { ...@@ -84,6 +84,7 @@ public class TestLob extends TestBase {
if (config.memory) { if (config.memory) {
return; return;
} }
testLargeClob();
testLobCleanupSessionTemporaries(); testLobCleanupSessionTemporaries();
testLobUpdateMany(); testLobUpdateMany();
testLobVariable(); testLobVariable();
...@@ -108,6 +109,27 @@ public class TestLob extends TestBase { ...@@ -108,6 +109,27 @@ public class TestLob extends TestBase {
deleteDb("lob"); 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 { private void testRemovedAfterTimeout() throws Exception {
deleteDb("lob"); deleteDb("lob");
final String url = getURL("lob;lob_timeout=50", true); final String url = getURL("lob;lob_timeout=50", true);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论