Unverified 提交 6616409f authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #773 from katzyn/JDBC

Better checks for arguments of partial LOB reading methods 
...@@ -262,6 +262,10 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -262,6 +262,10 @@ public class JdbcClob extends TraceObject implements NClob
/** /**
* Returns the reader, starting from an offset. * Returns the reader, starting from an offset.
*
* @param pos 1-based offset
* @param length length of requested area
* @return the reader
*/ */
@Override @Override
public Reader getCharacterStream(long pos, long length) throws SQLException { public Reader getCharacterStream(long pos, long length) throws SQLException {
......
/*
* Copyright 2004-2018 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; package org.h2.store;
import java.io.FilterInputStream; import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.h2.util.IOUtils;
/**
* Input stream that reads only a specified range from the source stream.
*/
public final class RangeInputStream extends FilterInputStream { public final class RangeInputStream extends FilterInputStream {
private long offset, limit; private long limit;
public RangeInputStream(InputStream in, long offset, long limit) { /**
* Creates new instance of range input stream.
*
* @param in
* source stream
* @param offset
* offset of the range
* @param limit
* length of the range
* @throws IOException
* on I/O exception during seeking to the specified offset
*/
public RangeInputStream(InputStream in, long offset, long limit) throws IOException {
super(in); super(in);
this.offset = offset;
this.limit = limit; this.limit = limit;
} IOUtils.skipFully(in, offset);
private void before() throws IOException {
while (offset > 0) {
offset -= in.skip(offset);
}
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
before();
if (limit < 1) { if (limit < 1) {
return -1; return -1;
} }
...@@ -34,7 +49,6 @@ public final class RangeInputStream extends FilterInputStream { ...@@ -34,7 +49,6 @@ public final class RangeInputStream extends FilterInputStream {
@Override @Override
public int read(byte b[], int off, int len) throws IOException { public int read(byte b[], int off, int len) throws IOException {
before();
if (len > limit) { if (len > limit) {
len = (int) limit; len = (int) limit;
} }
...@@ -47,7 +61,6 @@ public final class RangeInputStream extends FilterInputStream { ...@@ -47,7 +61,6 @@ public final class RangeInputStream extends FilterInputStream {
@Override @Override
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
before();
if (n > limit) { if (n > limit) {
n = (int) limit; n = (int) limit;
} }
...@@ -58,7 +71,6 @@ public final class RangeInputStream extends FilterInputStream { ...@@ -58,7 +71,6 @@ public final class RangeInputStream extends FilterInputStream {
@Override @Override
public int available() throws IOException { public int available() throws IOException {
before();
int cnt = in.available(); int cnt = in.available();
if (cnt > limit) { if (cnt > limit) {
return (int) limit; return (int) limit;
......
/*
* Copyright 2004-2018 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; package org.h2.store;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import org.h2.util.IOUtils;
/**
* Reader that reads only a specified range from the source reader.
*/
public final class RangeReader extends Reader { public final class RangeReader extends Reader {
private final Reader r; private final Reader r;
private long offset, limit; private long limit;
public RangeReader(Reader r, long offset, long limit) { /**
* Creates new instance of range reader.
*
* @param r
* source reader
* @param offset
* offset of the range
* @param limit
* length of the range
* @throws IOException
* on I/O exception during seeking to the specified offset
*/
public RangeReader(Reader r, long offset, long limit) throws IOException {
this.r = r; this.r = r;
this.offset = offset;
this.limit = limit; this.limit = limit;
} IOUtils.skipFully(r, offset);
private void before() throws IOException {
while (offset > 0) {
offset -= r.skip(offset);
}
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
before();
if (limit < 1) { if (limit < 1) {
return -1; return -1;
} }
...@@ -35,7 +50,6 @@ public final class RangeReader extends Reader { ...@@ -35,7 +50,6 @@ public final class RangeReader extends Reader {
@Override @Override
public int read(char cbuf[], int off, int len) throws IOException { public int read(char cbuf[], int off, int len) throws IOException {
before();
if (len > limit) { if (len > limit) {
len = (int) limit; len = (int) limit;
} }
...@@ -48,7 +62,6 @@ public final class RangeReader extends Reader { ...@@ -48,7 +62,6 @@ public final class RangeReader extends Reader {
@Override @Override
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
before();
if (n > limit) { if (n > limit) {
n = (int) limit; n = (int) limit;
} }
...@@ -59,7 +72,6 @@ public final class RangeReader extends Reader { ...@@ -59,7 +72,6 @@ public final class RangeReader extends Reader {
@Override @Override
public boolean ready() throws IOException { public boolean ready() throws IOException {
before();
if (limit > 0) { if (limit > 0) {
return r.ready(); return r.ready();
} }
......
...@@ -188,7 +188,7 @@ public abstract class Value { ...@@ -188,7 +188,7 @@ public abstract class Value {
private static final BigDecimal MIN_LONG_DECIMAL = private static final BigDecimal MIN_LONG_DECIMAL =
BigDecimal.valueOf(Long.MIN_VALUE); BigDecimal.valueOf(Long.MIN_VALUE);
private static void rangeCheck(long zeroBasedOffset, long length, long dataSize) { static void rangeCheck(long zeroBasedOffset, long length, long dataSize) {
if ((zeroBasedOffset | length) < 0 || length > dataSize - zeroBasedOffset) { if ((zeroBasedOffset | length) < 0 || length > dataSize - zeroBasedOffset) {
if (zeroBasedOffset < 0 || zeroBasedOffset > dataSize) { if (zeroBasedOffset < 0 || zeroBasedOffset > dataSize) {
throw DbException.getInvalidValueException("offset", zeroBasedOffset + 1); throw DbException.getInvalidValueException("offset", zeroBasedOffset + 1);
......
...@@ -59,14 +59,28 @@ public class ValueLob extends Value { ...@@ -59,14 +59,28 @@ public class ValueLob extends Value {
} }
} }
static InputStream rangeInputStream(InputStream inputStream, long oneBasedOffset, long length) { static InputStream rangeInputStream(InputStream inputStream, long oneBasedOffset, long length, long dataSize) {
rangeCheckUnknown(--oneBasedOffset, length); if (dataSize > 0)
return new RangeInputStream(inputStream, /* 0-based */ oneBasedOffset, length); rangeCheck(oneBasedOffset - 1, length, dataSize);
else
rangeCheckUnknown(oneBasedOffset - 1, length);
try {
return new RangeInputStream(inputStream, oneBasedOffset - 1, length);
} catch (IOException e) {
throw DbException.getInvalidValueException("offset", oneBasedOffset);
}
} }
static Reader rangeReader(Reader reader, long oneBasedOffset, long length) { static Reader rangeReader(Reader reader, long oneBasedOffset, long length, long dataSize) {
rangeCheckUnknown(--oneBasedOffset, length); if (dataSize > 0)
return new RangeReader(reader, /* 0-based */ oneBasedOffset, length); rangeCheck(oneBasedOffset - 1, length, dataSize);
else
rangeCheckUnknown(oneBasedOffset - 1, length);
try {
return new RangeReader(reader, oneBasedOffset - 1, length);
} catch (IOException e) {
throw DbException.getInvalidValueException("offset", oneBasedOffset);
}
} }
/** /**
...@@ -655,7 +669,7 @@ public class ValueLob extends Value { ...@@ -655,7 +669,7 @@ public class ValueLob extends Value {
@Override @Override
public Reader getReader(long oneBasedOffset, long length) { public Reader getReader(long oneBasedOffset, long length) {
return rangeReader(getReader(), oneBasedOffset, length); return rangeReader(getReader(), oneBasedOffset, length, type == Value.CLOB ? precision : -1);
} }
@Override @Override
...@@ -675,7 +689,12 @@ public class ValueLob extends Value { ...@@ -675,7 +689,12 @@ public class ValueLob extends Value {
if (fileName == null) { if (fileName == null) {
return super.getInputStream(oneBasedOffset, length); return super.getInputStream(oneBasedOffset, length);
} }
return rangeInputStream(getInputStream(), oneBasedOffset, length); FileStore store = handler.openFile(fileName, "r", true);
boolean alwaysClose = SysProperties.lobCloseBetweenReads;
InputStream inputStream = new BufferedInputStream(
new FileStoreInputStream(store, handler, compressed, alwaysClose),
Constants.IO_BUFFER_SIZE);
return rangeInputStream(inputStream, oneBasedOffset, length, store.length());
} }
@Override @Override
......
...@@ -376,7 +376,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -376,7 +376,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public Reader getReader(long oneBasedOffset, long length) { public Reader getReader(long oneBasedOffset, long length) {
return ValueLob.rangeReader(getReader(), oneBasedOffset, length); return ValueLob.rangeReader(getReader(), oneBasedOffset, length, type == Value.CLOB ? precision : -1);
} }
@Override @Override
...@@ -399,10 +399,25 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -399,10 +399,25 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public InputStream getInputStream(long oneBasedOffset, long length) { public InputStream getInputStream(long oneBasedOffset, long length) {
long byteCount;
InputStream inputStream;
if (small != null) { if (small != null) {
return super.getInputStream(oneBasedOffset, length); return super.getInputStream(oneBasedOffset, length);
} else if (fileName != null) {
FileStore store = handler.openFile(fileName, "r", true);
boolean alwaysClose = SysProperties.lobCloseBetweenReads;
byteCount = store.length();
inputStream = new BufferedInputStream(new FileStoreInputStream(store,
handler, false, alwaysClose), Constants.IO_BUFFER_SIZE);
} else {
byteCount = (type == Value.BLOB) ? precision : -1;
try {
inputStream = handler.getLobStorage().getInputStream(this, hmac, byteCount);
} catch (IOException e) {
throw DbException.convertIOException(e, toString());
}
} }
return ValueLob.rangeInputStream(getInputStream(), oneBasedOffset, length); return ValueLob.rangeInputStream(inputStream, oneBasedOffset, length, byteCount);
} }
@Override @Override
......
...@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit; ...@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase; import org.h2.test.TestBase;
...@@ -1102,6 +1103,8 @@ public class TestLob extends TestBase { ...@@ -1102,6 +1103,8 @@ public class TestLob extends TestBase {
fail("expected -1 got: " + ch); fail("expected -1 got: " + ch);
} }
r.close(); r.close();
assertThrows(ErrorCode.INVALID_VALUE_2, clob0).getCharacterStream(10001, 1);
assertThrows(ErrorCode.INVALID_VALUE_2, clob0).getCharacterStream(10002, 0);
conn0.close(); conn0.close();
} }
......
...@@ -1615,6 +1615,7 @@ public class TestResultSet extends TestBase { ...@@ -1615,6 +1615,7 @@ public class TestResultSet extends TestBase {
assertEqualsWithNull(new byte[] { (byte) 0x03, assertEqualsWithNull(new byte[] { (byte) 0x03,
(byte) 0x03 }, readAllBytes(blob.getBinaryStream(2, 2))); (byte) 0x03 }, readAllBytes(blob.getBinaryStream(2, 2)));
assertTrue(!rs.wasNull()); assertTrue(!rs.wasNull());
assertThrows(ErrorCode.INVALID_VALUE_2, blob).getBinaryStream(5, 1);
} finally { } finally {
blob.free(); blob.free();
} }
...@@ -1632,6 +1633,8 @@ public class TestResultSet extends TestBase { ...@@ -1632,6 +1633,8 @@ public class TestResultSet extends TestBase {
byte[] got = readAllBytes(blob.getBinaryStream(101, 50002)); byte[] got = readAllBytes(blob.getBinaryStream(101, 50002));
assertEqualsWithNull(expected, got); assertEqualsWithNull(expected, got);
assertTrue(!rs.wasNull()); assertTrue(!rs.wasNull());
assertThrows(ErrorCode.INVALID_VALUE_2, blob).getBinaryStream(0x10001, 1);
assertThrows(ErrorCode.INVALID_VALUE_2, blob).getBinaryStream(0x10002, 0);
} finally { } finally {
blob.free(); blob.free();
} }
...@@ -1695,6 +1698,8 @@ public class TestResultSet extends TestBase { ...@@ -1695,6 +1698,8 @@ public class TestResultSet extends TestBase {
Clob clob = rs.getClob(2); Clob clob = rs.getClob(2);
try { try {
assertEquals("all", readString(clob.getCharacterStream(2, 3))); assertEquals("all", readString(clob.getCharacterStream(2, 3)));
assertThrows(ErrorCode.INVALID_VALUE_2, clob).getCharacterStream(6, 1);
assertThrows(ErrorCode.INVALID_VALUE_2, clob).getCharacterStream(7, 0);
} finally { } finally {
clob.free(); clob.free();
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论