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
/**
* Returns the reader, starting from an offset.
*
* @param pos 1-based offset
* @param length length of requested area
* @return the reader
*/
@Override
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;
import java.io.FilterInputStream;
import java.io.IOException;
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 {
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);
this.offset = offset;
this.limit = limit;
}
private void before() throws IOException {
while (offset > 0) {
offset -= in.skip(offset);
}
IOUtils.skipFully(in, offset);
}
@Override
public int read() throws IOException {
before();
if (limit < 1) {
return -1;
}
......@@ -34,7 +49,6 @@ public final class RangeInputStream extends FilterInputStream {
@Override
public int read(byte b[], int off, int len) throws IOException {
before();
if (len > limit) {
len = (int) limit;
}
......@@ -47,7 +61,6 @@ public final class RangeInputStream extends FilterInputStream {
@Override
public long skip(long n) throws IOException {
before();
if (n > limit) {
n = (int) limit;
}
......@@ -58,7 +71,6 @@ public final class RangeInputStream extends FilterInputStream {
@Override
public int available() throws IOException {
before();
int cnt = in.available();
if (cnt > 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;
import java.io.IOException;
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 {
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.offset = offset;
this.limit = limit;
}
private void before() throws IOException {
while (offset > 0) {
offset -= r.skip(offset);
}
IOUtils.skipFully(r, offset);
}
@Override
public int read() throws IOException {
before();
if (limit < 1) {
return -1;
}
......@@ -35,7 +50,6 @@ public final class RangeReader extends Reader {
@Override
public int read(char cbuf[], int off, int len) throws IOException {
before();
if (len > limit) {
len = (int) limit;
}
......@@ -48,7 +62,6 @@ public final class RangeReader extends Reader {
@Override
public long skip(long n) throws IOException {
before();
if (n > limit) {
n = (int) limit;
}
......@@ -59,7 +72,6 @@ public final class RangeReader extends Reader {
@Override
public boolean ready() throws IOException {
before();
if (limit > 0) {
return r.ready();
}
......
......@@ -188,7 +188,7 @@ public abstract class Value {
private static final BigDecimal MIN_LONG_DECIMAL =
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 < 0 || zeroBasedOffset > dataSize) {
throw DbException.getInvalidValueException("offset", zeroBasedOffset + 1);
......
......@@ -59,14 +59,28 @@ public class ValueLob extends Value {
}
}
static InputStream rangeInputStream(InputStream inputStream, long oneBasedOffset, long length) {
rangeCheckUnknown(--oneBasedOffset, length);
return new RangeInputStream(inputStream, /* 0-based */ oneBasedOffset, length);
static InputStream rangeInputStream(InputStream inputStream, long oneBasedOffset, long length, long dataSize) {
if (dataSize > 0)
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) {
rangeCheckUnknown(--oneBasedOffset, length);
return new RangeReader(reader, /* 0-based */ oneBasedOffset, length);
static Reader rangeReader(Reader reader, long oneBasedOffset, long length, long dataSize) {
if (dataSize > 0)
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 {
@Override
public Reader getReader(long oneBasedOffset, long length) {
return rangeReader(getReader(), oneBasedOffset, length);
return rangeReader(getReader(), oneBasedOffset, length, type == Value.CLOB ? precision : -1);
}
@Override
......@@ -675,7 +689,12 @@ public class ValueLob extends Value {
if (fileName == null) {
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
......
......@@ -376,7 +376,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override
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
......@@ -399,10 +399,25 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override
public InputStream getInputStream(long oneBasedOffset, long length) {
long byteCount;
InputStream inputStream;
if (small != null) {
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
......
......@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.DbException;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
......@@ -1102,6 +1103,8 @@ public class TestLob extends TestBase {
fail("expected -1 got: " + ch);
}
r.close();
assertThrows(ErrorCode.INVALID_VALUE_2, clob0).getCharacterStream(10001, 1);
assertThrows(ErrorCode.INVALID_VALUE_2, clob0).getCharacterStream(10002, 0);
conn0.close();
}
......
......@@ -1615,6 +1615,7 @@ public class TestResultSet extends TestBase {
assertEqualsWithNull(new byte[] { (byte) 0x03,
(byte) 0x03 }, readAllBytes(blob.getBinaryStream(2, 2)));
assertTrue(!rs.wasNull());
assertThrows(ErrorCode.INVALID_VALUE_2, blob).getBinaryStream(5, 1);
} finally {
blob.free();
}
......@@ -1632,6 +1633,8 @@ public class TestResultSet extends TestBase {
byte[] got = readAllBytes(blob.getBinaryStream(101, 50002));
assertEqualsWithNull(expected, got);
assertTrue(!rs.wasNull());
assertThrows(ErrorCode.INVALID_VALUE_2, blob).getBinaryStream(0x10001, 1);
assertThrows(ErrorCode.INVALID_VALUE_2, blob).getBinaryStream(0x10002, 0);
} finally {
blob.free();
}
......@@ -1695,6 +1698,8 @@ public class TestResultSet extends TestBase {
Clob clob = rs.getClob(2);
try {
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 {
clob.free();
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论