提交 12e00f3a authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add abstract JdbcLob and make LOB state checks more reliable

上级 3bf8fd6a
......@@ -9,14 +9,12 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.sql.Blob;
import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.engine.Constants;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
......@@ -27,18 +25,13 @@ import org.h2.value.Value;
/**
* Represents a BLOB value.
*/
public class JdbcBlob extends TraceObject implements Blob {
Value value;
private final JdbcConnection conn;
public class JdbcBlob extends JdbcLob implements Blob {
/**
* INTERNAL
*/
public JdbcBlob(JdbcConnection conn, Value value, int id) {
setTrace(conn.getSession().getTrace(), TraceObject.BLOB, id);
this.conn = conn;
this.value = value;
public JdbcBlob(JdbcConnection conn, Value value, State state, int id) {
super(conn, value, state, TraceObject.BLOB, id);
}
/**
......@@ -50,7 +43,7 @@ public class JdbcBlob extends TraceObject implements Blob {
public long length() throws SQLException {
try {
debugCodeCall("length");
checkClosed();
checkReadable();
if (value.getType() == Value.BLOB) {
long precision = value.getPrecision();
if (precision > 0) {
......@@ -86,7 +79,7 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) {
debugCode("getBytes("+pos+", "+length+");");
}
checkClosed();
checkReadable();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (InputStream in = value.getInputStream()) {
IOUtils.skipFully(in, pos - 1);
......@@ -113,11 +106,11 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) {
debugCode("setBytes("+pos+", "+quoteBytes(bytes)+");");
}
checkClosed();
checkEditable();
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
}
value = conn.createBlob(new ByteArrayInputStream(bytes), -1);
completeWrite(conn.createBlob(new ByteArrayInputStream(bytes), -1));
return bytes.length;
} catch (Exception e) {
throw logAndConvert(e);
......@@ -140,31 +133,20 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) {
debugCode("setBytes(" + pos + ", " + quoteBytes(bytes) + ", " + offset + ", " + len + ");");
}
checkClosed();
checkEditable();
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
}
value = conn.createBlob(new ByteArrayInputStream(bytes, offset, len), -1);
completeWrite(conn.createBlob(new ByteArrayInputStream(bytes, offset, len), -1));
return (int) value.getPrecision();
} catch (Exception e) {
throw logAndConvert(e);
}
}
/**
* Returns the input stream.
*
* @return the input stream
*/
@Override
public InputStream getBinaryStream() throws SQLException {
try {
debugCodeCall("getBinaryStream");
checkClosed();
return value.getInputStream();
} catch (Exception e) {
throw logAndConvert(e);
}
return super.getBinaryStream();
}
/**
......@@ -183,33 +165,20 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) {
debugCode("setBinaryStream("+pos+");");
}
checkClosed();
checkEditable();
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
}
if (value.getPrecision() != 0) {
throw DbException.getInvalidValueException("length", value.getPrecision());
}
final JdbcConnection c = conn; // local variable avoids generating synthetic accessor method
final PipedInputStream in = new PipedInputStream();
final Task task = new Task() {
@Override
public void call() {
value = c.createBlob(in, -1);
}
};
PipedOutputStream out = new PipedOutputStream(in) {
@Override
public void close() throws IOException {
super.close();
try {
task.get();
} catch (Exception e) {
throw DbException.convertToIOException(e);
}
completeWrite(conn.createBlob(in, -1));
}
};
Output out = new Output(in, task);
task.execute();
state = State.SET_CALLED;
return new BufferedOutputStream(out);
} catch (Exception e) {
throw logAndConvert(e);
......@@ -230,7 +199,7 @@ public class JdbcBlob extends TraceObject implements Blob {
}
if (Constants.BLOB_SEARCH) {
try {
checkClosed();
checkReadable();
if (pattern == null) {
return -1;
}
......@@ -285,7 +254,7 @@ public class JdbcBlob extends TraceObject implements Blob {
}
if (Constants.BLOB_SEARCH) {
try {
checkClosed();
checkReadable();
if (blobPattern == null) {
return -1;
}
......@@ -306,15 +275,6 @@ public class JdbcBlob extends TraceObject implements Blob {
throw unsupported("LOB subset");
}
/**
* Release all resources of this object.
*/
@Override
public void free() {
debugCodeCall("free");
value = null;
}
/**
* Returns the input stream, starting from an offset.
*
......@@ -325,28 +285,22 @@ public class JdbcBlob extends TraceObject implements Blob {
@Override
public InputStream getBinaryStream(long pos, long length) throws SQLException {
try {
debugCodeCall("getBinaryStream(pos, length)");
checkClosed();
if (isDebugEnabled()) {
debugCode("getBinaryStream(" + pos + ", " + length + ");");
}
checkReadable();
if (state == State.NEW) {
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
}
if (length != 0) {
throw DbException.getInvalidValueException("length", pos);
}
}
return value.getInputStream(pos, length);
} catch (Exception e) {
throw logAndConvert(e);
}
}
private void checkClosed() {
conn.checkClosed();
if (value == null) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
}
/**
* INTERNAL
*/
@Override
public String toString() {
return getTraceObjectName() + ": " +
(value == null ? "null" : value.getTraceSQL());
}
}
......@@ -5,11 +5,8 @@
*/
package org.h2.jdbc;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
......@@ -17,31 +14,24 @@ import java.io.Writer;
import java.sql.Clob;
import java.sql.NClob;
import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.engine.Constants;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.store.RangeReader;
import org.h2.util.IOUtils;
import org.h2.util.Task;
import org.h2.value.Value;
/**
* Represents a CLOB value.
*/
public class JdbcClob extends TraceObject implements NClob
{
Value value;
private final JdbcConnection conn;
public class JdbcClob extends JdbcLob implements NClob {
/**
* INTERNAL
*/
public JdbcClob(JdbcConnection conn, Value value, int id) {
setTrace(conn.getSession().getTrace(), TraceObject.CLOB, id);
this.conn = conn;
this.value = value;
public JdbcClob(JdbcConnection conn, Value value, State state, int id) {
super(conn, value, state, TraceObject.CLOB, id);
}
/**
......@@ -53,7 +43,7 @@ public class JdbcClob extends TraceObject implements NClob
public long length() throws SQLException {
try {
debugCodeCall("length");
checkClosed();
checkReadable();
if (value.getType() == Value.CLOB) {
long precision = value.getPrecision();
if (precision > 0) {
......@@ -83,7 +73,7 @@ public class JdbcClob extends TraceObject implements NClob
public InputStream getAsciiStream() throws SQLException {
try {
debugCodeCall("getAsciiStream");
checkClosed();
checkReadable();
String s = value.getString();
return IOUtils.getInputStreamFromString(s);
} catch (Exception e) {
......@@ -99,20 +89,9 @@ public class JdbcClob extends TraceObject implements NClob
throw unsupported("LOB update");
}
/**
* Returns the reader.
*
* @return the reader
*/
@Override
public Reader getCharacterStream() throws SQLException {
try {
debugCodeCall("getCharacterStream");
checkClosed();
return value.getReader();
} catch (Exception e) {
throw logAndConvert(e);
}
return super.getCharacterStream();
}
/**
......@@ -129,39 +108,14 @@ public class JdbcClob extends TraceObject implements NClob
public Writer setCharacterStream(long pos) throws SQLException {
try {
if (isDebugEnabled()) {
debugCodeCall("setCharacterStream(" + pos + ");");
debugCode("setCharacterStream(" + pos + ");");
}
checkClosed();
checkEditable();
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
}
if (value.getPrecision() != 0) {
throw DbException.getInvalidValueException("length", value.getPrecision());
}
final JdbcConnection c = conn; // required to avoid synthetic method creation
// PipedReader / PipedWriter are a lot slower
// than PipedInputStream / PipedOutputStream
// (Sun/Oracle Java 1.6.0_20)
final PipedInputStream in = new PipedInputStream();
final Task task = new Task() {
@Override
public void call() {
value = c.createClob(IOUtils.getReader(in), -1);
}
};
PipedOutputStream out = new PipedOutputStream(in) {
@Override
public void close() throws IOException {
super.close();
try {
task.get();
} catch (Exception e) {
throw DbException.convertToIOException(e);
}
}
};
task.execute();
return IOUtils.getBufferedWriter(out);
state = State.SET_CALLED;
return setCharacterStreamImpl();
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -180,7 +134,7 @@ public class JdbcClob extends TraceObject implements NClob
if (isDebugEnabled()) {
debugCode("getSubString(" + pos + ", " + length + ");");
}
checkClosed();
checkReadable();
if (pos < 1) {
throw DbException.getInvalidValueException("pos", pos);
}
......@@ -214,13 +168,13 @@ public class JdbcClob extends TraceObject implements NClob
if (isDebugEnabled()) {
debugCode("setString(" + pos + ", " + quote(str) + ");");
}
checkClosed();
checkEditable();
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
} else if (str == null) {
throw DbException.getInvalidValueException("str", str);
}
value = conn.createClob(new StringReader(str), -1);
completeWrite(conn.createClob(new StringReader(str), -1));
return str.length();
} catch (Exception e) {
throw logAndConvert(e);
......@@ -245,13 +199,13 @@ public class JdbcClob extends TraceObject implements NClob
if (isDebugEnabled()) {
debugCode("setString(" + pos + ", " + quote(str) + ", " + offset + ", " + len + ");");
}
checkClosed();
checkEditable();
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
} else if (str == null) {
throw DbException.getInvalidValueException("str", str);
}
value = conn.createClob(new RangeReader(new StringReader(str), offset, len), -1);
completeWrite(conn.createClob(new RangeReader(new StringReader(str), offset, len), -1));
return (int) value.getPrecision();
} catch (Exception e) {
throw logAndConvert(e);
......@@ -274,15 +228,6 @@ public class JdbcClob extends TraceObject implements NClob
throw unsupported("LOB search");
}
/**
* Release all resources of this object.
*/
@Override
public void free() {
debugCodeCall("free");
value = null;
}
/**
* Returns the reader, starting from an offset.
*
......@@ -293,28 +238,22 @@ public class JdbcClob extends TraceObject implements NClob
@Override
public Reader getCharacterStream(long pos, long length) throws SQLException {
try {
debugCodeCall("getCharacterStream(pos, length)");
checkClosed();
if (isDebugEnabled()) {
debugCode("getCharacterStream(" + pos + ", " + length + ");");
}
checkReadable();
if (state == State.NEW) {
if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos);
}
if (length != 0) {
throw DbException.getInvalidValueException("length", pos);
}
}
return value.getReader(pos, length);
} catch (Exception e) {
throw logAndConvert(e);
}
}
private void checkClosed() {
conn.checkClosed();
if (value == null) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
}
/**
* INTERNAL
*/
@Override
public String toString() {
return getTraceObjectName() + ": " + (value == null ?
"null" : value.getTraceSQL());
}
}
......@@ -5,9 +5,7 @@
*/
package org.h2.jdbc;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.Array;
import java.sql.Blob;
......@@ -49,10 +47,10 @@ import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
import org.h2.util.CloseWatcher;
import org.h2.util.JdbcUtils;
import org.h2.util.Utils;
import org.h2.value.CompareMode;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueBytes;
import org.h2.value.ValueInt;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
......@@ -1614,16 +1612,7 @@ public class JdbcConnection extends TraceObject
int id = getNextId(TraceObject.CLOB);
debugCodeAssign("Clob", TraceObject.CLOB, id, "createClob()");
checkClosedForWrite();
try {
Value v = session.getDataHandler().getLobStorage()
.createClob(new InputStreamReader(
new ByteArrayInputStream(Utils.EMPTY_BYTES)),
0);
session.addTemporaryLob(v);
return new JdbcClob(this, v, id);
} finally {
afterWriting();
}
return new JdbcClob(this, ValueString.EMPTY, JdbcLob.State.NEW, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1640,16 +1629,7 @@ public class JdbcConnection extends TraceObject
int id = getNextId(TraceObject.BLOB);
debugCodeAssign("Blob", TraceObject.BLOB, id, "createClob()");
checkClosedForWrite();
try {
Value v = session.getDataHandler().getLobStorage().createBlob(
new ByteArrayInputStream(Utils.EMPTY_BYTES), 0);
synchronized (session) {
session.addTemporaryLob(v);
}
return new JdbcBlob(this, v, id);
} finally {
afterWriting();
}
return new JdbcBlob(this, ValueBytes.EMPTY, JdbcLob.State.NEW, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1666,16 +1646,7 @@ public class JdbcConnection extends TraceObject
int id = getNextId(TraceObject.CLOB);
debugCodeAssign("NClob", TraceObject.CLOB, id, "createNClob()");
checkClosedForWrite();
try {
Value v = session.getDataHandler().getLobStorage()
.createClob(new InputStreamReader(
new ByteArrayInputStream(Utils.EMPTY_BYTES)),
0);
session.addTemporaryLob(v);
return new JdbcClob(this, v, id);
} finally {
afterWriting();
}
return new JdbcClob(this, ValueString.EMPTY, JdbcLob.State.NEW, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -2069,11 +2040,11 @@ public class JdbcConnection extends TraceObject
switch (v.getType()) {
case Value.CLOB: {
int id = getNextId(TraceObject.CLOB);
return new JdbcClob(this, v, id);
return new JdbcClob(this, v, JdbcLob.State.WITH_VALUE, id);
}
case Value.BLOB: {
int id = getNextId(TraceObject.BLOB);
return new JdbcBlob(this, v, id);
return new JdbcBlob(this, v, JdbcLob.State.WITH_VALUE, id);
}
case Value.JAVA_OBJECT:
if (SysProperties.serializeJavaObject) {
......
/*
* 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.jdbc;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Reader;
import java.io.Writer;
import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.util.IOUtils;
import org.h2.util.Task;
import org.h2.value.Value;
/**
* Represents a large object value.
*/
public abstract class JdbcLob extends TraceObject {
final class Output extends PipedOutputStream {
private final Task task;
Output(PipedInputStream snk, Task task) throws IOException {
super(snk);
this.task = task;
}
@Override
public void close() throws IOException {
super.close();
try {
task.get();
} catch (Exception e) {
throw DbException.convertToIOException(e);
}
}
}
/**
* State of the object.
*/
public enum State {
/**
* New object without a value.
*/
NEW,
/**
* One of setter methods is invoked, but stream is not closed yet.
*/
SET_CALLED,
/**
* A value is set.
*/
WITH_VALUE,
/**
* Object is closed.
*/
CLOSED;
}
final JdbcConnection conn;
Value value;
State state;
JdbcLob(JdbcConnection conn, Value value, State state, int type, int id) {
setTrace(conn.getSession().getTrace(), type, id);
this.conn = conn;
this.value = value;
this.state = state;
}
void checkClosed() {
conn.checkClosed();
if (state == State.CLOSED) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
}
void checkEditable() {
checkClosed();
if (state != State.NEW) {
throw DbException.getUnsupportedException("Allocate a new object to set its value.");
}
}
void checkReadable() throws SQLException, IOException {
checkClosed();
if (state == State.SET_CALLED) {
throw DbException.getUnsupportedException("Stream setter is not yet closed.");
}
}
void completeWrite(Value blob) {
checkClosed();
state = State.WITH_VALUE;
value = blob;
}
/**
* Release all resources of this object.
*/
public void free() {
debugCodeCall("free");
state = State.CLOSED;
value = null;
}
/**
* Returns the input stream.
*
* @return the input stream
*/
InputStream getBinaryStream() throws SQLException {
try {
debugCodeCall("getBinaryStream");
checkReadable();
return value.getInputStream();
} catch (Exception e) {
throw logAndConvert(e);
}
}
/**
* Returns the reader.
*
* @return the reader
*/
Reader getCharacterStream() throws SQLException {
try {
debugCodeCall("getCharacterStream");
checkReadable();
return value.getReader();
} catch (Exception e) {
throw logAndConvert(e);
}
}
Writer setCharacterStreamImpl() throws IOException {
return IOUtils.getBufferedWriter(setClobOutputStreamImpl());
}
Output setClobOutputStreamImpl() throws IOException {
// PipedReader / PipedWriter are a lot slower
// than PipedInputStream / PipedOutputStream
// (Sun/Oracle Java 1.6.0_20)
final PipedInputStream in = new PipedInputStream();
final Task task = new Task() {
@Override
public void call() {
completeWrite(conn.createClob(IOUtils.getReader(in), -1));
}
};
Output out = new Output(in, task);
task.execute();
return out;
}
/**
* INTERNAL
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder().append(getTraceObjectName()).append(": ");
if (state == State.SET_CALLED) {
builder.append("<setter_in_progress>");
} else if (state == State.CLOSED) {
builder.append("<closed>");
} else {
builder.append(value.getTraceSQL());
}
return builder.toString();
}
}
......@@ -1024,7 +1024,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
id, "getBlob(" + columnIndex + ")");
}
Value v = get(columnIndex);
return v == ValueNull.INSTANCE ? null : new JdbcBlob(conn, v, id);
return v == ValueNull.INSTANCE ? null : new JdbcBlob(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1047,7 +1047,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
id, "getBlob(" + quote(columnLabel) + ")");
}
Value v = get(columnLabel);
return v == ValueNull.INSTANCE ? null : new JdbcBlob(conn, v, id);
return v == ValueNull.INSTANCE ? null : new JdbcBlob(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1142,7 +1142,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
debugCodeAssign("Clob", TraceObject.CLOB, id, "getClob(" + columnIndex + ")");
}
Value v = get(columnIndex);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, id);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1165,7 +1165,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
quote(columnLabel) + ")");
}
Value v = get(columnLabel);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, id);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -3399,11 +3399,15 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
}
/**
* [Not supported]
* Updates a column in the current or insert row.
*
* @param columnIndex (1,2,...)
* @param x the value
* @throws SQLException if the result set is closed or not updatable
*/
@Override
public void updateNClob(int columnIndex, NClob x) throws SQLException {
throw unsupported("NClob");
updateClob(columnIndex, x);
}
/**
......@@ -3459,11 +3463,15 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
}
/**
* [Not supported]
* Updates a column in the current or insert row.
*
* @param columnLabel the column label
* @param x the value
* @throws SQLException if the result set is closed or not updatable
*/
@Override
public void updateNClob(String columnLabel, NClob x) throws SQLException {
throw unsupported("NClob");
updateClob(columnLabel, x);
}
/**
......@@ -3482,7 +3490,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
debugCodeAssign("NClob", TraceObject.CLOB, id, "getNClob(" + columnIndex + ")");
}
Value v = get(columnIndex);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, id);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -3504,7 +3512,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
debugCodeAssign("NClob", TraceObject.CLOB, id, "getNClob(" + columnLabel + ")");
}
Value v = get(columnLabel);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, id);
return v == ValueNull.INSTANCE ? null : new JdbcClob(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -3811,10 +3819,12 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
return type.cast(value == ValueNull.INSTANCE ? null : new JdbcArray(conn, value, id));
} else if (type == Blob.class) {
int id = getNextId(TraceObject.BLOB);
return type.cast(value == ValueNull.INSTANCE ? null : new JdbcBlob(conn, value, id));
return type.cast(value == ValueNull.INSTANCE
? null : new JdbcBlob(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == Clob.class) {
int id = getNextId(TraceObject.CLOB);
return type.cast(value == ValueNull.INSTANCE ? null : new JdbcClob(conn, value, id));
return type.cast(value == ValueNull.INSTANCE
? null : new JdbcClob(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == TimestampWithTimeZone.class) {
return type.cast(value.getObject());
} else if (DataType.isGeometryClass(type)) {
......
......@@ -24,6 +24,7 @@ import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import org.h2.api.ErrorCode;
import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.Mode;
......@@ -33,6 +34,7 @@ import org.h2.jdbc.JdbcArray;
import org.h2.jdbc.JdbcBlob;
import org.h2.jdbc.JdbcClob;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcLob;
import org.h2.message.DbException;
import org.h2.tools.SimpleResultSet;
import org.h2.util.JdbcUtils;
......@@ -1365,9 +1367,9 @@ public class DataType {
public static Object convertTo(JdbcConnection conn, Value v,
Class<?> paramClass) {
if (paramClass == Blob.class) {
return new JdbcBlob(conn, v, 0);
return new JdbcBlob(conn, v, JdbcLob.State.WITH_VALUE, 0);
} else if (paramClass == Clob.class) {
return new JdbcClob(conn, v, 0);
return new JdbcClob(conn, v, JdbcLob.State.WITH_VALUE, 0);
} else if (paramClass == Array.class) {
return new JdbcArray(conn, v, 0);
}
......
......@@ -21,7 +21,10 @@ import org.h2.util.Utils;
*/
public class ValueBytes extends Value {
private static final ValueBytes EMPTY = new ValueBytes(Utils.EMPTY_BYTES);
/**
* Empty value.
*/
public static final ValueBytes EMPTY = new ValueBytes(Utils.EMPTY_BYTES);
/**
* The value.
......
......@@ -18,7 +18,11 @@ import org.h2.util.StringUtils;
*/
public class ValueString extends Value {
private static final ValueString EMPTY = new ValueString("");
/**
* Empty string. Should not be used in places where empty string can be
* treated as {@code NULL} depending on database mode.
*/
public static final ValueString EMPTY = new ValueString("");
/**
* The string data.
......
......@@ -81,7 +81,7 @@ public class TestLobApi extends TestDb {
assertEquals("x", new String(data, StandardCharsets.UTF_8));
assertTrue(clob.toString().endsWith("'x'"));
clob.free();
assertTrue(clob.toString().endsWith("null"));
assertTrue(clob.toString().endsWith("<closed>"));
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, clob).
truncate(0);
......@@ -101,7 +101,7 @@ public class TestLobApi extends TestDb {
position((Blob) null, 0);
assertTrue(blob.toString().endsWith("X'00'"));
blob.free();
assertTrue(blob.toString().endsWith("null"));
assertTrue(blob.toString().endsWith("<closed>"));
stat.execute("drop table test");
conn.close();
......
......@@ -20,7 +20,6 @@ import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
......@@ -178,10 +177,6 @@ public class TestResultSet extends TestDb {
updateRowId(1, (RowId) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
updateRowId("x", (RowId) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
updateNClob(1, (NClob) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
updateNClob("x", (NClob) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
updateSQLXML(1, (SQLXML) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论