Unverified 提交 11b7e7cd authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #1233 from grandinj/simplify_old_lob

Simplify old lob ValueLob class
...@@ -584,7 +584,6 @@ public class Data { ...@@ -584,7 +584,6 @@ public class Data {
writeByte((byte) type); writeByte((byte) type);
if (v instanceof ValueLob) { if (v instanceof ValueLob) {
ValueLob lob = (ValueLob) v; ValueLob lob = (ValueLob) v;
lob.convertToFileIfRequired(handler);
byte[] small = lob.getSmall(); byte[] small = lob.getSmall();
if (small == null) { if (small == null) {
int t = -1; int t = -1;
...@@ -1013,7 +1012,6 @@ public class Data { ...@@ -1013,7 +1012,6 @@ public class Data {
int len = 1; int len = 1;
if (v instanceof ValueLob) { if (v instanceof ValueLob) {
ValueLob lob = (ValueLob) v; ValueLob lob = (ValueLob) v;
lob.convertToFileIfRequired(handler);
byte[] small = lob.getSmall(); byte[] small = lob.getSmall();
if (small == null) { if (small == null) {
int t = -1; int t = -1;
......
...@@ -214,7 +214,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -214,7 +214,7 @@ public class Recover extends Tool implements DataHandler {
/** /**
* INTERNAL * INTERNAL
*/ */
public static Value.ValueBlob readBlobDb(Connection conn, long lobId, public static ValueLobDb readBlobDb(Connection conn, long lobId,
long precision) { long precision) {
DataHandler h = ((JdbcConnection) conn).getSession().getDataHandler(); DataHandler h = ((JdbcConnection) conn).getSession().getDataHandler();
verifyPageStore(h); verifyPageStore(h);
...@@ -235,7 +235,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -235,7 +235,7 @@ public class Recover extends Tool implements DataHandler {
/** /**
* INTERNAL * INTERNAL
*/ */
public static Value.ValueClob readClobDb(Connection conn, long lobId, public static ValueLobDb readClobDb(Connection conn, long lobId,
long precision) { long precision) {
DataHandler h = ((JdbcConnection) conn).getSession().getDataHandler(); DataHandler h = ((JdbcConnection) conn).getSession().getDataHandler();
verifyPageStore(h); verifyPageStore(h);
......
...@@ -995,10 +995,11 @@ public class DataType { ...@@ -995,10 +995,11 @@ public class DataType {
return Value.DECIMAL; return Value.DECIMAL;
} else if (ResultSet.class.isAssignableFrom(x)) { } else if (ResultSet.class.isAssignableFrom(x)) {
return Value.RESULT_SET; return Value.RESULT_SET;
} else if (Value.ValueBlob.class.isAssignableFrom(x)) { } else if (ValueLobDb.class.isAssignableFrom(x)) {
return Value.BLOB; return Value.BLOB;
} else if (Value.ValueClob.class.isAssignableFrom(x)) { // FIXME no way to distinguish between these 2 types
return Value.CLOB; // } else if (ValueLobDb.class.isAssignableFrom(x)) {
// return Value.CLOB;
} else if (Date.class.isAssignableFrom(x)) { } else if (Date.class.isAssignableFrom(x)) {
return Value.DATE; return Value.DATE;
} else if (Time.class.isAssignableFrom(x)) { } else if (Time.class.isAssignableFrom(x)) {
......
...@@ -1395,18 +1395,4 @@ public abstract class Value { ...@@ -1395,18 +1395,4 @@ public abstract class Value {
return null; return null;
} }
/**
* A "binary large object".
*/
public interface ValueClob {
// this is a marker interface
}
/**
* A "character large object".
*/
public interface ValueBlob {
// this is a marker interface
}
} }
...@@ -6,15 +6,12 @@ ...@@ -6,15 +6,12 @@
package org.h2.value; package org.h2.value;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
...@@ -22,7 +19,6 @@ import org.h2.message.DbException; ...@@ -22,7 +19,6 @@ import org.h2.message.DbException;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.store.FileStoreInputStream; import org.h2.store.FileStoreInputStream;
import org.h2.store.FileStoreOutputStream;
import org.h2.store.RangeInputStream; import org.h2.store.RangeInputStream;
import org.h2.store.RangeReader; import org.h2.store.RangeReader;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
...@@ -34,19 +30,8 @@ import org.h2.util.StringUtils; ...@@ -34,19 +30,8 @@ import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
/** /**
* Implementation of the BLOB and CLOB data types. Small objects are kept in * This is the legacy implementation of LOBs for PageStore databases where the
* memory and stored in the record. * LOB was stored in an external file.
*
* Large objects are stored in their own files. When large objects are set in a
* prepared statement, they are first stored as 'temporary' files. Later, when
* they are used in a record, and when the record is stored, the lob files are
* linked: the file is renamed using the file format (tableId).(objectId). There
* is one exception: large variables are stored in the file (-1).(objectId).
*
* When lobs are deleted, they are first renamed to a temp file, and if the
* delete operation is committed the file is deleted.
*
* Data compression is supported.
*/ */
public class ValueLob extends Value { public class ValueLob extends Value {
...@@ -109,22 +94,23 @@ public class ValueLob extends Value { ...@@ -109,22 +94,23 @@ public class ValueLob extends Value {
*/ */
private static int dirCounter; private static int dirCounter;
private final int type; /**
private long precision; * either Value.BLOB or Value.CLOB
private DataHandler handler; */
private final int valueType;
private final long precision;
private final DataHandler handler;
private int tableId; private int tableId;
private int objectId; private final int objectId;
private String fileName; private String fileName;
private boolean linked; private boolean linked;
private byte[] small;
private int hash; private int hash;
private boolean compressed; private final boolean compressed;
private FileStore tempFile;
private ValueLob(int type, DataHandler handler, String fileName, private ValueLob(int type, DataHandler handler, String fileName,
int tableId, int objectId, boolean linked, long precision, int tableId, int objectId, boolean linked, long precision,
boolean compressed) { boolean compressed) {
this.type = type; this.valueType = type;
this.handler = handler; this.handler = handler;
this.fileName = fileName; this.fileName = fileName;
this.tableId = tableId; this.tableId = tableId;
...@@ -134,37 +120,6 @@ public class ValueLob extends Value { ...@@ -134,37 +120,6 @@ public class ValueLob extends Value {
this.compressed = compressed; this.compressed = compressed;
} }
private ValueLob(int type, byte[] small) {
this.type = type;
this.small = small;
if (small != null) {
if (type == Value.BLOB) {
this.precision = small.length;
} else {
this.precision = getString().length();
}
}
}
private static ValueLob copy(ValueLob lob) {
ValueLob copy = new ValueLob(lob.type, lob.handler, lob.fileName,
lob.tableId, lob.objectId, lob.linked, lob.precision, lob.compressed);
copy.small = lob.small;
copy.hash = lob.hash;
return copy;
}
/**
* Create a small lob using the given byte array.
*
* @param type the type (Value.BLOB or CLOB)
* @param small the byte array
* @return the lob value
*/
private static ValueLob createSmallLob(int type, byte[] small) {
return new ValueLob(type, small);
}
private static String getFileName(DataHandler handler, int tableId, private static String getFileName(DataHandler handler, int tableId,
int objectId) { int objectId) {
if (SysProperties.CHECK && tableId == 0 && objectId == 0) { if (SysProperties.CHECK && tableId == 0 && objectId == 0) {
...@@ -178,7 +133,7 @@ public class ValueLob extends Value { ...@@ -178,7 +133,7 @@ public class ValueLob extends Value {
/** /**
* Create a LOB value with the given parameters. * Create a LOB value with the given parameters.
* *
* @param type the data type * @param type the data type, either Value.BLOB or Value.CLOB
* @param handler the file handler * @param handler the file handler
* @param tableId the table object id * @param tableId the table object id
* @param objectId the object id * @param objectId the object id
...@@ -196,7 +151,7 @@ public class ValueLob extends Value { ...@@ -196,7 +151,7 @@ public class ValueLob extends Value {
/** /**
* Create a LOB value with the given parameters. * Create a LOB value with the given parameters.
* *
* @param type the data type * @param type the data type, either Value.BLOB or Value.CLOB
* @param handler the file handler * @param handler the file handler
* @param tableId the table object id * @param tableId the table object id
* @param objectId the object id * @param objectId the object id
...@@ -212,92 +167,6 @@ public class ValueLob extends Value { ...@@ -212,92 +167,6 @@ public class ValueLob extends Value {
false/* linked */, precision, compression); false/* linked */, precision, compression);
} }
/**
* Create a CLOB value from a stream.
*
* @param in the reader
* @param length the number of characters to read, or -1 for no limit
* @param handler the data handler
* @return the lob value
*/
private static ValueLob createClob(Reader in, long length,
DataHandler handler) {
try {
if (handler == null) {
String s = IOUtils.readStringAndClose(in, (int) length);
return createSmallLob(Value.CLOB, s.getBytes(StandardCharsets.UTF_8));
}
boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null;
long remaining = Long.MAX_VALUE;
if (length >= 0 && length < remaining) {
remaining = length;
}
int len = getBufferSize(handler, compress, remaining);
char[] buff;
if (len >= Integer.MAX_VALUE) {
String data = IOUtils.readStringAndClose(in, -1);
buff = data.toCharArray();
len = buff.length;
} else {
buff = new char[len];
len = IOUtils.readFully(in, buff, len);
}
if (len <= handler.getMaxLengthInplaceLob()) {
byte[] small = new String(buff, 0, len).getBytes(StandardCharsets.UTF_8);
return ValueLob.createSmallLob(Value.CLOB, small);
}
ValueLob lob = new ValueLob(Value.CLOB, null);
lob.createFromReader(buff, len, in, remaining, handler);
return lob;
} catch (IOException e) {
throw DbException.convertIOException(e, null);
}
}
private static int getBufferSize(DataHandler handler, boolean compress,
long remaining) {
if (remaining < 0 || remaining > Integer.MAX_VALUE) {
remaining = Integer.MAX_VALUE;
}
int inplace = handler.getMaxLengthInplaceLob();
long m = compress ?
Constants.IO_BUFFER_SIZE_COMPRESS : Constants.IO_BUFFER_SIZE;
if (m < remaining && m <= inplace) {
// using "1L" to force long arithmetic
m = Math.min(remaining, inplace + 1L);
// the buffer size must be bigger than the inplace lob, otherwise we
// can't know if it must be stored in-place or not
m = MathUtils.roundUpLong(m, Constants.IO_BUFFER_SIZE);
}
m = Math.min(remaining, m);
m = MathUtils.convertLongToInt(m);
if (m < 0) {
m = Integer.MAX_VALUE;
}
return (int) m;
}
private void createFromReader(char[] buff, int len, Reader in,
long remaining, DataHandler h) throws IOException {
try (FileStoreOutputStream out = initLarge(h)) {
boolean compress = h.getLobCompressionAlgorithm(Value.CLOB) != null;
while (true) {
precision += len;
byte[] b = new String(buff, 0, len).getBytes(StandardCharsets.UTF_8);
out.write(b, 0, b.length);
remaining -= len;
if (remaining <= 0) {
break;
}
len = getBufferSize(h, compress, remaining);
len = IOUtils.readFully(in, buff, len);
if (len == 0) {
break;
}
}
}
}
private static String getFileNamePrefix(String path, int objectId) { private static String getFileNamePrefix(String path, int objectId) {
String name; String name;
int f = objectId % SysProperties.LOB_FILES_PER_DIRECTORY; int f = objectId % SysProperties.LOB_FILES_PER_DIRECTORY;
...@@ -406,91 +275,6 @@ public class ValueLob extends Value { ...@@ -406,91 +275,6 @@ public class ValueLob extends Value {
return list; return list;
} }
/**
* Create a BLOB value from a stream.
*
* @param in the input stream
* @param length the number of characters to read, or -1 for no limit
* @param handler the data handler
* @return the lob value
*/
private static ValueLob createBlob(InputStream in, long length,
DataHandler handler) {
try {
if (handler == null) {
byte[] data = IOUtils.readBytesAndClose(in, (int) length);
return createSmallLob(Value.BLOB, data);
}
long remaining = Long.MAX_VALUE;
boolean compress = handler.getLobCompressionAlgorithm(Value.BLOB) != null;
if (length >= 0 && length < remaining) {
remaining = length;
}
int len = getBufferSize(handler, compress, remaining);
byte[] buff;
if (len >= Integer.MAX_VALUE) {
buff = IOUtils.readBytesAndClose(in, -1);
len = buff.length;
} else {
buff = Utils.newBytes(len);
len = IOUtils.readFully(in, buff, len);
}
if (len <= handler.getMaxLengthInplaceLob()) {
byte[] small = Utils.copyBytes(buff, len);
return ValueLob.createSmallLob(Value.BLOB, small);
}
ValueLob lob = new ValueLob(Value.BLOB, null);
lob.createFromStream(buff, len, in, remaining, handler);
return lob;
} catch (IOException e) {
throw DbException.convertIOException(e, null);
}
}
private FileStoreOutputStream initLarge(DataHandler h) {
this.handler = h;
this.tableId = 0;
this.linked = false;
this.precision = 0;
this.small = null;
this.hash = 0;
String compressionAlgorithm = h.getLobCompressionAlgorithm(type);
this.compressed = compressionAlgorithm != null;
synchronized (h) {
String path = h.getDatabasePath();
if ((path != null) && (path.length() == 0)) {
path = new File(Utils.getProperty("java.io.tmpdir", "."),
SysProperties.PREFIX_TEMP_FILE).getAbsolutePath();
}
objectId = getNewObjectId(h);
fileName = getFileNamePrefix(path, objectId) + Constants.SUFFIX_TEMP_FILE;
tempFile = h.openFile(fileName, "rw", false);
tempFile.autoDelete();
}
return new FileStoreOutputStream(tempFile, h,
compressionAlgorithm);
}
private void createFromStream(byte[] buff, int len, InputStream in,
long remaining, DataHandler h) throws IOException {
try (FileStoreOutputStream out = initLarge(h)) {
boolean compress = h.getLobCompressionAlgorithm(Value.BLOB) != null;
while (true) {
precision += len;
out.write(buff, 0, len);
remaining -= len;
if (remaining <= 0) {
break;
}
len = getBufferSize(h, compress, remaining);
len = IOUtils.readFully(in, buff, len);
if (len <= 0) {
break;
}
}
}
}
/** /**
* Convert a lob to another data type. The data is fully read in memory * Convert a lob to another data type. The data is fully read in memory
* except when converting to BLOB or CLOB. * except when converting to BLOB or CLOB.
...@@ -507,12 +291,12 @@ public class ValueLob extends Value { ...@@ -507,12 +291,12 @@ public class ValueLob extends Value {
*/ */
@Override @Override
public Value convertTo(int t, int precision, Mode mode, Object column, String[] enumerators) { public Value convertTo(int t, int precision, Mode mode, Object column, String[] enumerators) {
if (t == type) { if (t == valueType) {
return this; return this;
} else if (t == Value.CLOB) { } else if (t == Value.CLOB) {
return ValueLob.createClob(getReader(), -1, handler); return ValueLobDb.createTempClob(getReader(), -1, handler);
} else if (t == Value.BLOB) { } else if (t == Value.BLOB) {
return ValueLob.createBlob(getInputStream(), -1, handler); return ValueLobDb.createTempBlob(getInputStream(), -1, handler);
} }
return super.convertTo(t, precision, mode, column, null); return super.convertTo(t, precision, mode, column, null);
} }
...@@ -533,24 +317,15 @@ public class ValueLob extends Value { ...@@ -533,24 +317,15 @@ public class ValueLob extends Value {
@Override @Override
public void remove() { public void remove() {
if (fileName != null) {
if (tempFile != null) {
tempFile.stopAutoDelete();
tempFile = null;
}
deleteFile(handler, fileName); deleteFile(handler, fileName);
} }
}
@Override @Override
public Value copy(DataHandler h, int tabId) { public Value copy(DataHandler h, int tabId) {
if (fileName == null) {
this.tableId = tabId;
return this;
}
if (linked) { if (linked) {
ValueLob copy = ValueLob.copy(this); ValueLob copy = new ValueLob(this.valueType, this.handler, this.fileName,
copy.objectId = getNewObjectId(h); this.tableId, getNewObjectId(h), this.linked, this.precision, this.compressed);
copy.hash = this.hash;
copy.tableId = tabId; copy.tableId = tabId;
String live = getFileName(h, copy.tableId, copy.objectId); String live = getFileName(h, copy.tableId, copy.objectId);
copyFileTo(h, fileName, live); copyFileTo(h, fileName, live);
...@@ -561,10 +336,6 @@ public class ValueLob extends Value { ...@@ -561,10 +336,6 @@ public class ValueLob extends Value {
if (!linked) { if (!linked) {
this.tableId = tabId; this.tableId = tabId;
String live = getFileName(h, tableId, objectId); String live = getFileName(h, tableId, objectId);
if (tempFile != null) {
tempFile.stopAutoDelete();
tempFile = null;
}
renameFile(h, fileName, live); renameFile(h, fileName, live);
fileName = live; fileName = live;
linked = true; linked = true;
...@@ -593,7 +364,7 @@ public class ValueLob extends Value { ...@@ -593,7 +364,7 @@ public class ValueLob extends Value {
@Override @Override
public int getType() { public int getType() {
return type; return valueType;
} }
@Override @Override
...@@ -606,18 +377,10 @@ public class ValueLob extends Value { ...@@ -606,18 +377,10 @@ public class ValueLob extends Value {
int len = precision > Integer.MAX_VALUE || precision == 0 ? int len = precision > Integer.MAX_VALUE || precision == 0 ?
Integer.MAX_VALUE : (int) precision; Integer.MAX_VALUE : (int) precision;
try { try {
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
if (small != null) {
return new String(small, StandardCharsets.UTF_8);
}
return IOUtils.readStringAndClose(getReader(), len); return IOUtils.readStringAndClose(getReader(), len);
} }
byte[] buff; byte[] buff = IOUtils.readBytesAndClose(getInputStream(), len);
if (small != null) {
buff = small;
} else {
buff = IOUtils.readBytesAndClose(getInputStream(), len);
}
return StringUtils.convertBytesToHex(buff); return StringUtils.convertBytesToHex(buff);
} catch (IOException e) { } catch (IOException e) {
throw DbException.convertIOException(e, fileName); throw DbException.convertIOException(e, fileName);
...@@ -626,7 +389,7 @@ public class ValueLob extends Value { ...@@ -626,7 +389,7 @@ public class ValueLob extends Value {
@Override @Override
public byte[] getBytes() { public byte[] getBytes() {
if (type == CLOB) { if (valueType == CLOB) {
// convert hex to string // convert hex to string
return super.getBytes(); return super.getBytes();
} }
...@@ -636,13 +399,10 @@ public class ValueLob extends Value { ...@@ -636,13 +399,10 @@ public class ValueLob extends Value {
@Override @Override
public byte[] getBytesNoCopy() { public byte[] getBytesNoCopy() {
if (type == CLOB) { if (valueType == CLOB) {
// convert hex to string // convert hex to string
return super.getBytesNoCopy(); return super.getBytesNoCopy();
} }
if (small != null) {
return small;
}
try { try {
return IOUtils.readBytesAndClose( return IOUtils.readBytesAndClose(
getInputStream(), Integer.MAX_VALUE); getInputStream(), Integer.MAX_VALUE);
...@@ -659,7 +419,7 @@ public class ValueLob extends Value { ...@@ -659,7 +419,7 @@ public class ValueLob extends Value {
// it in the database file // it in the database file
return (int) (precision ^ (precision >>> 32)); return (int) (precision ^ (precision >>> 32));
} }
if (type == CLOB) { if (valueType == CLOB) {
hash = getString().hashCode(); hash = getString().hashCode();
} else { } else {
hash = Utils.getByteArrayHash(getBytes()); hash = Utils.getByteArrayHash(getBytes());
...@@ -670,7 +430,7 @@ public class ValueLob extends Value { ...@@ -670,7 +430,7 @@ public class ValueLob extends Value {
@Override @Override
protected int compareSecure(Value v, CompareMode mode) { protected int compareSecure(Value v, CompareMode mode) {
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
return Integer.signum(getString().compareTo(v.getString())); return Integer.signum(getString().compareTo(v.getString()));
} }
byte[] v2 = v.getBytesNoCopy(); byte[] v2 = v.getBytesNoCopy();
...@@ -679,7 +439,7 @@ public class ValueLob extends Value { ...@@ -679,7 +439,7 @@ public class ValueLob extends Value {
@Override @Override
public Object getObject() { public Object getObject() {
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
return getReader(); return getReader();
} }
return getInputStream(); return getInputStream();
...@@ -692,14 +452,11 @@ public class ValueLob extends Value { ...@@ -692,14 +452,11 @@ 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, type == Value.CLOB ? precision : -1); return rangeReader(getReader(), oneBasedOffset, length, valueType == Value.CLOB ? precision : -1);
} }
@Override @Override
public InputStream getInputStream() { public InputStream getInputStream() {
if (fileName == null) {
return new ByteArrayInputStream(small);
}
FileStore store = handler.openFile(fileName, "r", true); FileStore store = handler.openFile(fileName, "r", true);
boolean alwaysClose = SysProperties.lobCloseBetweenReads; boolean alwaysClose = SysProperties.lobCloseBetweenReads;
return new BufferedInputStream( return new BufferedInputStream(
...@@ -709,9 +466,6 @@ public class ValueLob extends Value { ...@@ -709,9 +466,6 @@ public class ValueLob extends Value {
@Override @Override
public InputStream getInputStream(long oneBasedOffset, long length) { public InputStream getInputStream(long oneBasedOffset, long length) {
if (fileName == null) {
return super.getInputStream(oneBasedOffset, length);
}
FileStore store = handler.openFile(fileName, "r", true); FileStore store = handler.openFile(fileName, "r", true);
boolean alwaysClose = SysProperties.lobCloseBetweenReads; boolean alwaysClose = SysProperties.lobCloseBetweenReads;
InputStream inputStream = new BufferedInputStream( InputStream inputStream = new BufferedInputStream(
...@@ -727,7 +481,7 @@ public class ValueLob extends Value { ...@@ -727,7 +481,7 @@ public class ValueLob extends Value {
if (p > Integer.MAX_VALUE || p <= 0) { if (p > Integer.MAX_VALUE || p <= 0) {
p = -1; p = -1;
} }
if (type == Value.BLOB) { if (valueType == Value.BLOB) {
prep.setBinaryStream(parameterIndex, getInputStream(), (int) p); prep.setBinaryStream(parameterIndex, getInputStream(), (int) p);
} else { } else {
prep.setCharacterStream(parameterIndex, getReader(), (int) p); prep.setCharacterStream(parameterIndex, getReader(), (int) p);
...@@ -737,7 +491,7 @@ public class ValueLob extends Value { ...@@ -737,7 +491,7 @@ public class ValueLob extends Value {
@Override @Override
public String getSQL() { public String getSQL() {
String s; String s;
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
s = getString(); s = getString();
return StringUtils.quoteStringSQL(s); return StringUtils.quoteStringSQL(s);
} }
...@@ -748,11 +502,8 @@ public class ValueLob extends Value { ...@@ -748,11 +502,8 @@ public class ValueLob extends Value {
@Override @Override
public String getTraceSQL() { public String getTraceSQL() {
if (small != null && getPrecision() <= SysProperties.MAX_TRACE_DATA_LENGTH) {
return getSQL();
}
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
buff.append("SPACE(").append(getPrecision()); buff.append("SPACE(").append(getPrecision());
} else { } else {
buff.append("CAST(REPEAT('00', ").append(getPrecision()).append(") AS BINARY"); buff.append("CAST(REPEAT('00', ").append(getPrecision()).append(") AS BINARY");
...@@ -768,7 +519,7 @@ public class ValueLob extends Value { ...@@ -768,7 +519,7 @@ public class ValueLob extends Value {
*/ */
@Override @Override
public byte[] getSmall() { public byte[] getSmall() {
return small; return null;
} }
@Override @Override
...@@ -781,35 +532,6 @@ public class ValueLob extends Value { ...@@ -781,35 +532,6 @@ public class ValueLob extends Value {
return other instanceof ValueLob && compareSecure((Value) other, null) == 0; return other instanceof ValueLob && compareSecure((Value) other, null) == 0;
} }
/**
* Store the lob data to a file if the size of the buffer is larger than the
* maximum size for an in-place lob.
*
* @param h the data handler
*/
public void convertToFileIfRequired(DataHandler h) {
try {
if (small != null && small.length > h.getMaxLengthInplaceLob()) {
boolean compress = h.getLobCompressionAlgorithm(type) != null;
int len = getBufferSize(h, compress, Long.MAX_VALUE);
int tabId = tableId;
if (type == Value.BLOB) {
createFromStream(
Utils.newBytes(len), 0, getInputStream(), Long.MAX_VALUE, h);
} else {
createFromReader(
new char[len], 0, getReader(), Long.MAX_VALUE, h);
}
Value v2 = copy(h, tabId);
if (SysProperties.CHECK && v2 != this) {
DbException.throwInternalError(v2.toString());
}
}
} catch (IOException e) {
throw DbException.convertIOException(e, null);
}
}
/** /**
* Check if this lob value is compressed. * Check if this lob value is compressed.
* *
...@@ -848,9 +570,6 @@ public class ValueLob extends Value { ...@@ -848,9 +570,6 @@ public class ValueLob extends Value {
@Override @Override
public int getMemory() { public int getMemory() {
if (small != null) {
return small.length + 104;
}
return 140; return 140;
} }
...@@ -861,12 +580,12 @@ public class ValueLob extends Value { ...@@ -861,12 +580,12 @@ public class ValueLob extends Value {
* @return the value * @return the value
*/ */
@Override @Override
public ValueLob copyToTemp() { public ValueLobDb copyToTemp() {
ValueLob lob; ValueLobDb lob;
if (type == CLOB) { if (valueType == CLOB) {
lob = ValueLob.createClob(getReader(), precision, handler); lob = ValueLobDb.createTempClob(getReader(), precision, handler);
} else { } else {
lob = ValueLob.createBlob(getInputStream(), precision, handler); lob = ValueLobDb.createTempBlob(getInputStream(), precision, handler);
} }
return lob; return lob;
} }
...@@ -876,11 +595,11 @@ public class ValueLob extends Value { ...@@ -876,11 +595,11 @@ public class ValueLob extends Value {
if (this.precision <= precision) { if (this.precision <= precision) {
return this; return this;
} }
ValueLob lob; ValueLobDb lob;
if (type == CLOB) { if (valueType == CLOB) {
lob = ValueLob.createClob(getReader(), precision, handler); lob = ValueLobDb.createTempClob(getReader(), precision, handler);
} else { } else {
lob = ValueLob.createBlob(getInputStream(), precision, handler); lob = ValueLobDb.createTempBlob(getInputStream(), precision, handler);
} }
return lob; return lob;
} }
......
...@@ -39,10 +39,12 @@ import org.h2.util.Utils; ...@@ -39,10 +39,12 @@ import org.h2.util.Utils;
* Small objects are kept in memory and stored in the record. * Small objects are kept in memory and stored in the record.
* Large objects are either stored in the database, or in temporary files. * Large objects are either stored in the database, or in temporary files.
*/ */
public class ValueLobDb extends Value implements Value.ValueClob, public class ValueLobDb extends Value {
Value.ValueBlob {
private final int type; /**
* the value type (Value.BLOB or CLOB)
*/
private final int valueType;
private final long lobId; private final long lobId;
private final byte[] hmac; private final byte[] hmac;
private final byte[] small; private final byte[] small;
...@@ -66,7 +68,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -66,7 +68,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
private ValueLobDb(int type, DataHandler handler, int tableId, long lobId, private ValueLobDb(int type, DataHandler handler, int tableId, long lobId,
byte[] hmac, long precision) { byte[] hmac, long precision) {
this.type = type; this.valueType = type;
this.handler = handler; this.handler = handler;
this.tableId = tableId; this.tableId = tableId;
this.lobId = lobId; this.lobId = lobId;
...@@ -78,7 +80,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -78,7 +80,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
} }
private ValueLobDb(int type, byte[] small, long precision) { private ValueLobDb(int type, byte[] small, long precision) {
this.type = type; this.valueType = type;
this.small = small; this.small = small;
this.precision = precision; this.precision = precision;
this.lobId = 0; this.lobId = 0;
...@@ -94,7 +96,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -94,7 +96,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/ */
private ValueLobDb(DataHandler handler, Reader in, long remaining) private ValueLobDb(DataHandler handler, Reader in, long remaining)
throws IOException { throws IOException {
this.type = Value.CLOB; this.valueType = Value.CLOB;
this.handler = handler; this.handler = handler;
this.small = null; this.small = null;
this.lobId = 0; this.lobId = 0;
...@@ -126,7 +128,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -126,7 +128,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/ */
private ValueLobDb(DataHandler handler, byte[] buff, int len, InputStream in, private ValueLobDb(DataHandler handler, byte[] buff, int len, InputStream in,
long remaining) throws IOException { long remaining) throws IOException {
this.type = Value.BLOB; this.valueType = Value.BLOB;
this.handler = handler; this.handler = handler;
this.small = null; this.small = null;
this.lobId = 0; this.lobId = 0;
...@@ -167,7 +169,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -167,7 +169,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
/** /**
* Create a LOB value. * Create a LOB value.
* *
* @param type the type * @param type the type (Value.BLOB or CLOB)
* @param handler the data handler * @param handler the data handler
* @param tableId the table id * @param tableId the table id
* @param id the lob id * @param id the lob id
...@@ -194,7 +196,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -194,7 +196,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/ */
@Override @Override
public Value convertTo(int t, int precision, Mode mode, Object column, String[] enumerators) { public Value convertTo(int t, int precision, Mode mode, Object column, String[] enumerators) {
if (t == type) { if (t == valueType) {
return this; return this;
} else if (t == Value.CLOB) { } else if (t == Value.CLOB) {
if (handler != null) { if (handler != null) {
...@@ -248,7 +250,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -248,7 +250,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
} else if (small.length > database.getMaxLengthInplaceLob()) { } else if (small.length > database.getMaxLengthInplaceLob()) {
LobStorageInterface s = database.getLobStorage(); LobStorageInterface s = database.getLobStorage();
Value v; Value v;
if (type == Value.BLOB) { if (valueType == Value.BLOB) {
v = s.createBlob(getInputStream(), getPrecision()); v = s.createBlob(getInputStream(), getPrecision());
} else { } else {
v = s.createClob(getReader(), getPrecision()); v = s.createClob(getReader(), getPrecision());
...@@ -272,7 +274,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -272,7 +274,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public int getType() { public int getType() {
return type; return valueType;
} }
@Override @Override
...@@ -285,7 +287,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -285,7 +287,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
int len = precision > Integer.MAX_VALUE || precision == 0 ? int len = precision > Integer.MAX_VALUE || precision == 0 ?
Integer.MAX_VALUE : (int) precision; Integer.MAX_VALUE : (int) precision;
try { try {
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
if (small != null) { if (small != null) {
return new String(small, StandardCharsets.UTF_8); return new String(small, StandardCharsets.UTF_8);
} }
...@@ -305,7 +307,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -305,7 +307,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public byte[] getBytes() { public byte[] getBytes() {
if (type == CLOB) { if (valueType == CLOB) {
// convert hex to string // convert hex to string
return super.getBytes(); return super.getBytes();
} }
...@@ -315,7 +317,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -315,7 +317,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public byte[] getBytesNoCopy() { public byte[] getBytesNoCopy() {
if (type == CLOB) { if (valueType == CLOB) {
// convert hex to string // convert hex to string
return super.getBytesNoCopy(); return super.getBytesNoCopy();
} }
...@@ -337,7 +339,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -337,7 +339,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
// it in the database file // it in the database file
return (int) (precision ^ (precision >>> 32)); return (int) (precision ^ (precision >>> 32));
} }
if (type == CLOB) { if (valueType == CLOB) {
hash = getString().hashCode(); hash = getString().hashCode();
} else { } else {
hash = Utils.getByteArrayHash(getBytes()); hash = Utils.getByteArrayHash(getBytes());
...@@ -357,7 +359,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -357,7 +359,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
return 0; return 0;
} }
} }
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
return Integer.signum(getString().compareTo(v.getString())); return Integer.signum(getString().compareTo(v.getString()));
} }
byte[] v2 = v.getBytesNoCopy(); byte[] v2 = v.getBytesNoCopy();
...@@ -366,7 +368,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -366,7 +368,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public Object getObject() { public Object getObject() {
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
return getReader(); return getReader();
} }
return getInputStream(); return getInputStream();
...@@ -379,7 +381,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -379,7 +381,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, type == Value.CLOB ? precision : -1); return ValueLob.rangeReader(getReader(), oneBasedOffset, length, valueType == Value.CLOB ? precision : -1);
} }
@Override @Override
...@@ -392,7 +394,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -392,7 +394,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
return new BufferedInputStream(new FileStoreInputStream(store, return new BufferedInputStream(new FileStoreInputStream(store,
handler, false, alwaysClose), Constants.IO_BUFFER_SIZE); handler, false, alwaysClose), Constants.IO_BUFFER_SIZE);
} }
long byteCount = (type == Value.BLOB) ? precision : -1; long byteCount = (valueType == Value.BLOB) ? precision : -1;
try { try {
return handler.getLobStorage().getInputStream(this, hmac, byteCount); return handler.getLobStorage().getInputStream(this, hmac, byteCount);
} catch (IOException e) { } catch (IOException e) {
...@@ -413,7 +415,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -413,7 +415,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
inputStream = new BufferedInputStream(new FileStoreInputStream(store, inputStream = new BufferedInputStream(new FileStoreInputStream(store,
handler, false, alwaysClose), Constants.IO_BUFFER_SIZE); handler, false, alwaysClose), Constants.IO_BUFFER_SIZE);
} else { } else {
byteCount = (type == Value.BLOB) ? precision : -1; byteCount = (valueType == Value.BLOB) ? precision : -1;
try { try {
inputStream = handler.getLobStorage().getInputStream(this, hmac, byteCount); inputStream = handler.getLobStorage().getInputStream(this, hmac, byteCount);
} catch (IOException e) { } catch (IOException e) {
...@@ -430,7 +432,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -430,7 +432,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
if (p > Integer.MAX_VALUE || p <= 0) { if (p > Integer.MAX_VALUE || p <= 0) {
p = -1; p = -1;
} }
if (type == Value.BLOB) { if (valueType == Value.BLOB) {
prep.setBinaryStream(parameterIndex, getInputStream(), (int) p); prep.setBinaryStream(parameterIndex, getInputStream(), (int) p);
} else { } else {
prep.setCharacterStream(parameterIndex, getReader(), (int) p); prep.setCharacterStream(parameterIndex, getReader(), (int) p);
...@@ -440,7 +442,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -440,7 +442,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
@Override @Override
public String getSQL() { public String getSQL() {
String s; String s;
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
s = getString(); s = getString();
return StringUtils.quoteStringSQL(s); return StringUtils.quoteStringSQL(s);
} }
...@@ -455,7 +457,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -455,7 +457,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
return getSQL(); return getSQL();
} }
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
if (type == Value.CLOB) { if (valueType == Value.CLOB) {
buff.append("SPACE(").append(getPrecision()); buff.append("SPACE(").append(getPrecision());
} else { } else {
buff.append("CAST(REPEAT('00', ").append(getPrecision()).append(") AS BINARY"); buff.append("CAST(REPEAT('00', ").append(getPrecision()).append(") AS BINARY");
...@@ -650,13 +652,13 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -650,13 +652,13 @@ public class ValueLobDb extends Value implements Value.ValueClob,
return this; return this;
} }
ValueLobDb lob; ValueLobDb lob;
if (type == CLOB) { if (valueType == CLOB) {
if (handler == null) { if (handler == null) {
try { try {
int p = MathUtils.convertLongToInt(precision); int p = MathUtils.convertLongToInt(precision);
String s = IOUtils.readStringAndClose(getReader(), p); String s = IOUtils.readStringAndClose(getReader(), p);
byte[] data = s.getBytes(StandardCharsets.UTF_8); byte[] data = s.getBytes(StandardCharsets.UTF_8);
lob = ValueLobDb.createSmallLob(type, data, s.length()); lob = ValueLobDb.createSmallLob(valueType, data, s.length());
} catch (IOException e) { } catch (IOException e) {
throw DbException.convertIOException(e, null); throw DbException.convertIOException(e, null);
} }
...@@ -668,7 +670,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -668,7 +670,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
try { try {
int p = MathUtils.convertLongToInt(precision); int p = MathUtils.convertLongToInt(precision);
byte[] data = IOUtils.readBytesAndClose(getInputStream(), p); byte[] data = IOUtils.readBytesAndClose(getInputStream(), p);
lob = ValueLobDb.createSmallLob(type, data, data.length); lob = ValueLobDb.createSmallLob(valueType, data, data.length);
} catch (IOException e) { } catch (IOException e) {
throw DbException.convertIOException(e, null); throw DbException.convertIOException(e, null);
} }
......
...@@ -265,8 +265,9 @@ public class TestValue extends TestDb { ...@@ -265,8 +265,9 @@ public class TestValue extends TestDb {
testDataType(Value.NULL, Void.class); testDataType(Value.NULL, Void.class);
testDataType(Value.DECIMAL, BigDecimal.class); testDataType(Value.DECIMAL, BigDecimal.class);
testDataType(Value.RESULT_SET, ResultSet.class); testDataType(Value.RESULT_SET, ResultSet.class);
testDataType(Value.BLOB, Value.ValueBlob.class); testDataType(Value.BLOB, ValueLobDb.class);
testDataType(Value.CLOB, Value.ValueClob.class); // see FIXME in DataType.getTypeFromClass
//testDataType(Value.CLOB, Value.ValueClob.class);
testDataType(Value.DATE, Date.class); testDataType(Value.DATE, Date.class);
testDataType(Value.TIME, Time.class); testDataType(Value.TIME, Time.class);
testDataType(Value.TIMESTAMP, Timestamp.class); testDataType(Value.TIMESTAMP, Timestamp.class);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论