Unverified 提交 144f743e authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1242 from katzyn/SQLXML

Add implementation of SQLXML interface
...@@ -9,14 +9,12 @@ import java.io.BufferedInputStream; ...@@ -9,14 +9,12 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.sql.Blob; import java.sql.Blob;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.TraceObject; import org.h2.message.TraceObject;
...@@ -27,18 +25,13 @@ import org.h2.value.Value; ...@@ -27,18 +25,13 @@ import org.h2.value.Value;
/** /**
* Represents a BLOB value. * Represents a BLOB value.
*/ */
public class JdbcBlob extends TraceObject implements Blob { public class JdbcBlob extends JdbcLob implements Blob {
Value value;
private final JdbcConnection conn;
/** /**
* INTERNAL * INTERNAL
*/ */
public JdbcBlob(JdbcConnection conn, Value value, int id) { public JdbcBlob(JdbcConnection conn, Value value, State state, int id) {
setTrace(conn.getSession().getTrace(), TraceObject.BLOB, id); super(conn, value, state, TraceObject.BLOB, id);
this.conn = conn;
this.value = value;
} }
/** /**
...@@ -50,7 +43,7 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -50,7 +43,7 @@ public class JdbcBlob extends TraceObject implements Blob {
public long length() throws SQLException { public long length() throws SQLException {
try { try {
debugCodeCall("length"); debugCodeCall("length");
checkClosed(); checkReadable();
if (value.getType() == Value.BLOB) { if (value.getType() == Value.BLOB) {
long precision = value.getPrecision(); long precision = value.getPrecision();
if (precision > 0) { if (precision > 0) {
...@@ -86,7 +79,7 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -86,7 +79,7 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("getBytes("+pos+", "+length+");"); debugCode("getBytes("+pos+", "+length+");");
} }
checkClosed(); checkReadable();
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
try (InputStream in = value.getInputStream()) { try (InputStream in = value.getInputStream()) {
IOUtils.skipFully(in, pos - 1); IOUtils.skipFully(in, pos - 1);
...@@ -113,11 +106,11 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -113,11 +106,11 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("setBytes("+pos+", "+quoteBytes(bytes)+");"); debugCode("setBytes("+pos+", "+quoteBytes(bytes)+");");
} }
checkClosed(); checkEditable();
if (pos != 1) { if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos); throw DbException.getInvalidValueException("pos", pos);
} }
value = conn.createBlob(new ByteArrayInputStream(bytes), -1); completeWrite(conn.createBlob(new ByteArrayInputStream(bytes), -1));
return bytes.length; return bytes.length;
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
...@@ -140,31 +133,20 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -140,31 +133,20 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("setBytes(" + pos + ", " + quoteBytes(bytes) + ", " + offset + ", " + len + ");"); debugCode("setBytes(" + pos + ", " + quoteBytes(bytes) + ", " + offset + ", " + len + ");");
} }
checkClosed(); checkEditable();
if (pos != 1) { if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos); 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(); return (int) value.getPrecision();
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
} }
/**
* Returns the input stream.
*
* @return the input stream
*/
@Override @Override
public InputStream getBinaryStream() throws SQLException { public InputStream getBinaryStream() throws SQLException {
try { return super.getBinaryStream();
debugCodeCall("getBinaryStream");
checkClosed();
return value.getInputStream();
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
...@@ -183,33 +165,20 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -183,33 +165,20 @@ public class JdbcBlob extends TraceObject implements Blob {
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("setBinaryStream("+pos+");"); debugCode("setBinaryStream("+pos+");");
} }
checkClosed(); checkEditable();
if (pos != 1) { if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos); 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 PipedInputStream in = new PipedInputStream();
final Task task = new Task() { final Task task = new Task() {
@Override @Override
public void call() { public void call() {
value = c.createBlob(in, -1); completeWrite(conn.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);
}
} }
}; };
LobPipedOutputStream out = new LobPipedOutputStream(in, task);
task.execute(); task.execute();
state = State.SET_CALLED;
return new BufferedOutputStream(out); return new BufferedOutputStream(out);
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
...@@ -230,7 +199,7 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -230,7 +199,7 @@ public class JdbcBlob extends TraceObject implements Blob {
} }
if (Constants.BLOB_SEARCH) { if (Constants.BLOB_SEARCH) {
try { try {
checkClosed(); checkReadable();
if (pattern == null) { if (pattern == null) {
return -1; return -1;
} }
...@@ -285,7 +254,7 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -285,7 +254,7 @@ public class JdbcBlob extends TraceObject implements Blob {
} }
if (Constants.BLOB_SEARCH) { if (Constants.BLOB_SEARCH) {
try { try {
checkClosed(); checkReadable();
if (blobPattern == null) { if (blobPattern == null) {
return -1; return -1;
} }
...@@ -306,15 +275,6 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -306,15 +275,6 @@ public class JdbcBlob extends TraceObject implements Blob {
throw unsupported("LOB subset"); 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. * Returns the input stream, starting from an offset.
* *
...@@ -325,28 +285,22 @@ public class JdbcBlob extends TraceObject implements Blob { ...@@ -325,28 +285,22 @@ public class JdbcBlob extends TraceObject implements Blob {
@Override @Override
public InputStream getBinaryStream(long pos, long length) throws SQLException { public InputStream getBinaryStream(long pos, long length) throws SQLException {
try { try {
debugCodeCall("getBinaryStream(pos, length)"); if (isDebugEnabled()) {
checkClosed(); 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); return value.getInputStream(pos, length);
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(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 @@ ...@@ -5,11 +5,8 @@
*/ */
package org.h2.jdbc; package org.h2.jdbc;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
...@@ -17,31 +14,24 @@ import java.io.Writer; ...@@ -17,31 +14,24 @@ import java.io.Writer;
import java.sql.Clob; import java.sql.Clob;
import java.sql.NClob; import java.sql.NClob;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.TraceObject; import org.h2.message.TraceObject;
import org.h2.store.RangeReader; import org.h2.store.RangeReader;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.Task;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
* Represents a CLOB value. * Represents a CLOB value.
*/ */
public class JdbcClob extends TraceObject implements NClob public class JdbcClob extends JdbcLob implements NClob {
{
Value value;
private final JdbcConnection conn;
/** /**
* INTERNAL * INTERNAL
*/ */
public JdbcClob(JdbcConnection conn, Value value, int id) { public JdbcClob(JdbcConnection conn, Value value, State state, int id) {
setTrace(conn.getSession().getTrace(), TraceObject.CLOB, id); super(conn, value, state, TraceObject.CLOB, id);
this.conn = conn;
this.value = value;
} }
/** /**
...@@ -53,7 +43,7 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -53,7 +43,7 @@ public class JdbcClob extends TraceObject implements NClob
public long length() throws SQLException { public long length() throws SQLException {
try { try {
debugCodeCall("length"); debugCodeCall("length");
checkClosed(); checkReadable();
if (value.getType() == Value.CLOB) { if (value.getType() == Value.CLOB) {
long precision = value.getPrecision(); long precision = value.getPrecision();
if (precision > 0) { if (precision > 0) {
...@@ -83,7 +73,7 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -83,7 +73,7 @@ public class JdbcClob extends TraceObject implements NClob
public InputStream getAsciiStream() throws SQLException { public InputStream getAsciiStream() throws SQLException {
try { try {
debugCodeCall("getAsciiStream"); debugCodeCall("getAsciiStream");
checkClosed(); checkReadable();
String s = value.getString(); String s = value.getString();
return IOUtils.getInputStreamFromString(s); return IOUtils.getInputStreamFromString(s);
} catch (Exception e) { } catch (Exception e) {
...@@ -99,20 +89,9 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -99,20 +89,9 @@ public class JdbcClob extends TraceObject implements NClob
throw unsupported("LOB update"); throw unsupported("LOB update");
} }
/**
* Returns the reader.
*
* @return the reader
*/
@Override @Override
public Reader getCharacterStream() throws SQLException { public Reader getCharacterStream() throws SQLException {
try { return super.getCharacterStream();
debugCodeCall("getCharacterStream");
checkClosed();
return value.getReader();
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
...@@ -129,39 +108,14 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -129,39 +108,14 @@ public class JdbcClob extends TraceObject implements NClob
public Writer setCharacterStream(long pos) throws SQLException { public Writer setCharacterStream(long pos) throws SQLException {
try { try {
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCodeCall("setCharacterStream(" + pos + ");"); debugCode("setCharacterStream(" + pos + ");");
} }
checkClosed(); checkEditable();
if (pos != 1) { if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos); throw DbException.getInvalidValueException("pos", pos);
} }
if (value.getPrecision() != 0) { state = State.SET_CALLED;
throw DbException.getInvalidValueException("length", value.getPrecision()); return setCharacterStreamImpl();
}
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);
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -180,7 +134,7 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -180,7 +134,7 @@ public class JdbcClob extends TraceObject implements NClob
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("getSubString(" + pos + ", " + length + ");"); debugCode("getSubString(" + pos + ", " + length + ");");
} }
checkClosed(); checkReadable();
if (pos < 1) { if (pos < 1) {
throw DbException.getInvalidValueException("pos", pos); throw DbException.getInvalidValueException("pos", pos);
} }
...@@ -214,13 +168,13 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -214,13 +168,13 @@ public class JdbcClob extends TraceObject implements NClob
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("setString(" + pos + ", " + quote(str) + ");"); debugCode("setString(" + pos + ", " + quote(str) + ");");
} }
checkClosed(); checkEditable();
if (pos != 1) { if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos); throw DbException.getInvalidValueException("pos", pos);
} else if (str == null) { } else if (str == null) {
throw DbException.getInvalidValueException("str", str); throw DbException.getInvalidValueException("str", str);
} }
value = conn.createClob(new StringReader(str), -1); completeWrite(conn.createClob(new StringReader(str), -1));
return str.length(); return str.length();
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
...@@ -245,13 +199,13 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -245,13 +199,13 @@ public class JdbcClob extends TraceObject implements NClob
if (isDebugEnabled()) { if (isDebugEnabled()) {
debugCode("setString(" + pos + ", " + quote(str) + ", " + offset + ", " + len + ");"); debugCode("setString(" + pos + ", " + quote(str) + ", " + offset + ", " + len + ");");
} }
checkClosed(); checkEditable();
if (pos != 1) { if (pos != 1) {
throw DbException.getInvalidValueException("pos", pos); throw DbException.getInvalidValueException("pos", pos);
} else if (str == null) { } else if (str == null) {
throw DbException.getInvalidValueException("str", str); 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(); return (int) value.getPrecision();
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
...@@ -274,15 +228,6 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -274,15 +228,6 @@ public class JdbcClob extends TraceObject implements NClob
throw unsupported("LOB search"); 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. * Returns the reader, starting from an offset.
* *
...@@ -293,28 +238,22 @@ public class JdbcClob extends TraceObject implements NClob ...@@ -293,28 +238,22 @@ public class JdbcClob extends TraceObject implements NClob
@Override @Override
public Reader getCharacterStream(long pos, long length) throws SQLException { public Reader getCharacterStream(long pos, long length) throws SQLException {
try { try {
debugCodeCall("getCharacterStream(pos, length)"); if (isDebugEnabled()) {
checkClosed(); 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); return value.getReader(pos, length);
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(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 @@ ...@@ -5,9 +5,7 @@
*/ */
package org.h2.jdbc; package org.h2.jdbc;
import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.sql.Array; import java.sql.Array;
import java.sql.Blob; import java.sql.Blob;
...@@ -49,10 +47,10 @@ import org.h2.message.TraceObject; ...@@ -49,10 +47,10 @@ import org.h2.message.TraceObject;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.util.CloseWatcher; import org.h2.util.CloseWatcher;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.Utils;
import org.h2.value.CompareMode; import org.h2.value.CompareMode;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBytes;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueString; import org.h2.value.ValueString;
...@@ -1614,16 +1612,7 @@ public class JdbcConnection extends TraceObject ...@@ -1614,16 +1612,7 @@ public class JdbcConnection extends TraceObject
int id = getNextId(TraceObject.CLOB); int id = getNextId(TraceObject.CLOB);
debugCodeAssign("Clob", TraceObject.CLOB, id, "createClob()"); debugCodeAssign("Clob", TraceObject.CLOB, id, "createClob()");
checkClosedForWrite(); checkClosedForWrite();
try { return new JdbcClob(this, ValueString.EMPTY, JdbcLob.State.NEW, id);
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();
}
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -1640,16 +1629,7 @@ public class JdbcConnection extends TraceObject ...@@ -1640,16 +1629,7 @@ public class JdbcConnection extends TraceObject
int id = getNextId(TraceObject.BLOB); int id = getNextId(TraceObject.BLOB);
debugCodeAssign("Blob", TraceObject.BLOB, id, "createClob()"); debugCodeAssign("Blob", TraceObject.BLOB, id, "createClob()");
checkClosedForWrite(); checkClosedForWrite();
try { return new JdbcBlob(this, ValueBytes.EMPTY, JdbcLob.State.NEW, id);
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();
}
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -1666,27 +1646,27 @@ public class JdbcConnection extends TraceObject ...@@ -1666,27 +1646,27 @@ public class JdbcConnection extends TraceObject
int id = getNextId(TraceObject.CLOB); int id = getNextId(TraceObject.CLOB);
debugCodeAssign("NClob", TraceObject.CLOB, id, "createNClob()"); debugCodeAssign("NClob", TraceObject.CLOB, id, "createNClob()");
checkClosedForWrite(); checkClosedForWrite();
try { return new JdbcClob(this, ValueString.EMPTY, JdbcLob.State.NEW, id);
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();
}
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
} }
/** /**
* [Not supported] Create a new empty SQLXML object. * Create a new SQLXML object with no data.
*
* @return the object
*/ */
@Override @Override
public SQLXML createSQLXML() throws SQLException { public SQLXML createSQLXML() throws SQLException {
throw unsupported("SQLXML"); try {
int id = getNextId(TraceObject.SQLXML);
debugCodeAssign("SQLXML", TraceObject.SQLXML, id, "createSQLXML()");
checkClosedForWrite();
return new JdbcSQLXML(this, ValueString.EMPTY, JdbcLob.State.NEW, id);
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
...@@ -2069,11 +2049,11 @@ public class JdbcConnection extends TraceObject ...@@ -2069,11 +2049,11 @@ public class JdbcConnection extends TraceObject
switch (v.getType()) { switch (v.getType()) {
case Value.CLOB: { case Value.CLOB: {
int id = getNextId(TraceObject.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: { case Value.BLOB: {
int id = getNextId(TraceObject.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: case Value.JAVA_OBJECT:
if (SysProperties.serializeJavaObject) { 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 LobPipedOutputStream extends PipedOutputStream {
private final Task task;
LobPipedOutputStream(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());
}
LobPipedOutputStream 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));
}
};
LobPipedOutputStream out = new LobPipedOutputStream(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();
}
}
...@@ -1777,11 +1777,29 @@ public class JdbcPreparedStatement extends JdbcStatement implements ...@@ -1777,11 +1777,29 @@ public class JdbcPreparedStatement extends JdbcStatement implements
} }
/** /**
* [Not supported] Sets the value of a parameter as a SQLXML object. * Sets the value of a parameter as a SQLXML.
*
* @param parameterIndex the parameter index (1, 2, ...)
* @param x the value
* @throws SQLException if this object is closed
*/ */
@Override @Override
public void setSQLXML(int parameterIndex, SQLXML x) throws SQLException { public void setSQLXML(int parameterIndex, SQLXML x) throws SQLException {
throw unsupported("SQLXML"); try {
if (isDebugEnabled()) {
debugCode("setSQLXML("+parameterIndex+", x);");
}
checkClosedForWrite();
Value v;
if (x == null) {
v = ValueNull.INSTANCE;
} else {
v = conn.createClob(x.getCharacterStream(), -1);
}
setParameter(parameterIndex, v);
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
......
...@@ -1024,7 +1024,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -1024,7 +1024,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
id, "getBlob(" + columnIndex + ")"); id, "getBlob(" + columnIndex + ")");
} }
Value v = get(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) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -1047,7 +1047,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -1047,7 +1047,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
id, "getBlob(" + quote(columnLabel) + ")"); id, "getBlob(" + quote(columnLabel) + ")");
} }
Value v = get(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) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -1142,7 +1142,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -1142,7 +1142,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
debugCodeAssign("Clob", TraceObject.CLOB, id, "getClob(" + columnIndex + ")"); debugCodeAssign("Clob", TraceObject.CLOB, id, "getClob(" + columnIndex + ")");
} }
Value v = get(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) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -1165,7 +1165,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -1165,7 +1165,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
quote(columnLabel) + ")"); quote(columnLabel) + ")");
} }
Value v = get(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) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -3399,11 +3399,15 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -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 @Override
public void updateNClob(int columnIndex, NClob x) throws SQLException { 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 ...@@ -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 @Override
public void updateNClob(String columnLabel, NClob x) throws SQLException { 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 ...@@ -3482,7 +3490,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
debugCodeAssign("NClob", TraceObject.CLOB, id, "getNClob(" + columnIndex + ")"); debugCodeAssign("NClob", TraceObject.CLOB, id, "getNClob(" + columnIndex + ")");
} }
Value v = get(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) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
...@@ -3504,46 +3512,108 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -3504,46 +3512,108 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
debugCodeAssign("NClob", TraceObject.CLOB, id, "getNClob(" + columnLabel + ")"); debugCodeAssign("NClob", TraceObject.CLOB, id, "getNClob(" + columnLabel + ")");
} }
Value v = get(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) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
} }
/** /**
* [Not supported] Returns the value of the specified column as a SQLXML * Returns the value of the specified column as a SQLXML.
* object. *
* @param columnIndex (1,2,...)
* @return the value
* @throws SQLException if the column is not found or if the result set is
* closed
*/ */
@Override @Override
public SQLXML getSQLXML(int columnIndex) throws SQLException { public SQLXML getSQLXML(int columnIndex) throws SQLException {
throw unsupported("SQLXML"); try {
int id = getNextId(TraceObject.SQLXML);
if (isDebugEnabled()) {
debugCodeAssign("SQLXML", TraceObject.SQLXML, id, "getSQLXML(" + columnIndex + ")");
}
Value v = get(columnIndex);
return v == ValueNull.INSTANCE ? null : new JdbcSQLXML(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
* [Not supported] Returns the value of the specified column as a SQLXML * Returns the value of the specified column as a SQLXML.
* object. *
* @param columnLabel the column label
* @return the value
* @throws SQLException if the column is not found or if the result set is
* closed
*/ */
@Override @Override
public SQLXML getSQLXML(String columnLabel) throws SQLException { public SQLXML getSQLXML(String columnLabel) throws SQLException {
throw unsupported("SQLXML"); try {
int id = getNextId(TraceObject.SQLXML);
if (isDebugEnabled()) {
debugCodeAssign("SQLXML", TraceObject.SQLXML, id, "getSQLXML(" + columnLabel + ")");
}
Value v = get(columnLabel);
return v == ValueNull.INSTANCE ? null : new JdbcSQLXML(conn, v, JdbcLob.State.WITH_VALUE, id);
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
* [Not supported] Updates a column in the current or insert row. * 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 @Override
public void updateSQLXML(int columnIndex, SQLXML xmlObject) public void updateSQLXML(int columnIndex, SQLXML xmlObject)
throws SQLException { throws SQLException {
throw unsupported("SQLXML"); try {
if (isDebugEnabled()) {
debugCode("updateSQLXML("+columnIndex+", x);");
}
checkClosed();
Value v;
if (xmlObject == null) {
v = ValueNull.INSTANCE;
} else {
v = conn.createClob(xmlObject.getCharacterStream(), -1);
}
update(columnIndex, v);
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
* [Not supported] Updates a column in the current or insert row. * 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 @Override
public void updateSQLXML(String columnLabel, SQLXML xmlObject) public void updateSQLXML(String columnLabel, SQLXML xmlObject)
throws SQLException { throws SQLException {
throw unsupported("SQLXML"); try {
if (isDebugEnabled()) {
debugCode("updateSQLXML("+quote(columnLabel)+", x);");
}
checkClosed();
Value v;
if (xmlObject == null) {
v = ValueNull.INSTANCE;
} else {
v = conn.createClob(xmlObject.getCharacterStream(), -1);
}
update(columnLabel, v);
} catch (Exception e) {
throw logAndConvert(e);
}
} }
/** /**
...@@ -3811,10 +3881,16 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -3811,10 +3881,16 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
return type.cast(value == ValueNull.INSTANCE ? null : new JdbcArray(conn, value, id)); return type.cast(value == ValueNull.INSTANCE ? null : new JdbcArray(conn, value, id));
} else if (type == Blob.class) { } else if (type == Blob.class) {
int id = getNextId(TraceObject.BLOB); 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) { } else if (type == Clob.class) {
int id = getNextId(TraceObject.CLOB); 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 == SQLXML.class) {
int id = getNextId(TraceObject.SQLXML);
return type.cast(value == ValueNull.INSTANCE
? null : new JdbcSQLXML(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == TimestampWithTimeZone.class) { } else if (type == TimestampWithTimeZone.class) {
return type.cast(value.getObject()); return type.cast(value.getObject());
} else if (DataType.isGeometryClass(type)) { } else if (DataType.isGeometryClass(type)) {
......
/*
* 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.BufferedOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.SQLException;
import java.sql.SQLXML;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stax.StAXResult;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.value.Value;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/**
* Represents a SQLXML value.
*/
public class JdbcSQLXML extends JdbcLob implements SQLXML {
private DOMResult domResult;
/**
* Underlying stream for SAXResult, StAXResult, and StreamResult.
*/
private Closeable closable;
/**
* INTERNAL
*/
public JdbcSQLXML(JdbcConnection conn, Value value, State state, int id) {
super(conn, value, state, TraceObject.SQLXML, id);
}
@Override
void checkReadable() throws SQLException, IOException {
checkClosed();
if (state == State.SET_CALLED) {
if (domResult != null) {
Node node = domResult.getNode();
domResult = null;
TransformerFactory factory = TransformerFactory.newInstance();
try {
Transformer transformer = factory.newTransformer();
DOMSource domSource = new DOMSource(node);
StringWriter stringWriter = new StringWriter();
StreamResult streamResult = new StreamResult(stringWriter);
transformer.transform(domSource, streamResult);
completeWrite(conn.createClob(new StringReader(stringWriter.toString()), -1));
} catch (Exception e) {
throw logAndConvert(e);
}
return;
} else if (closable != null) {
closable.close();
closable = null;
return;
}
throw DbException.getUnsupportedException("Stream setter is not yet closed.");
}
}
@Override
public InputStream getBinaryStream() throws SQLException {
return super.getBinaryStream();
}
@Override
public Reader getCharacterStream() throws SQLException {
return super.getCharacterStream();
}
@SuppressWarnings("unchecked")
@Override
public <T extends Source> T getSource(Class<T> sourceClass) throws SQLException {
try {
if (isDebugEnabled()) {
debugCodeCall(
"getSource(" + (sourceClass != null ? sourceClass.getSimpleName() + ".class" : "null") + ')');
}
checkReadable();
if (sourceClass == null || sourceClass == DOMSource.class) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
return (T) new DOMSource(dbf.newDocumentBuilder().parse(new InputSource(value.getInputStream())));
} else if (sourceClass == SAXSource.class) {
return (T) new SAXSource(new InputSource(value.getInputStream()));
} else if (sourceClass == StAXSource.class) {
XMLInputFactory xif = XMLInputFactory.newInstance();
return (T) new StAXSource(xif.createXMLStreamReader(value.getInputStream()));
} else if (sourceClass == StreamSource.class) {
return (T) new StreamSource(value.getInputStream());
}
throw unsupported(sourceClass.getName());
} catch (Exception e) {
throw logAndConvert(e);
}
}
@Override
public String getString() throws SQLException {
try {
debugCodeCall("getString");
checkReadable();
return value.getString();
} catch (Exception e) {
throw logAndConvert(e);
}
}
@Override
public OutputStream setBinaryStream() throws SQLException {
try {
debugCodeCall("setBinaryStream");
checkEditable();
state = State.SET_CALLED;
return new BufferedOutputStream(setClobOutputStreamImpl());
} catch (Exception e) {
throw logAndConvert(e);
}
}
@Override
public Writer setCharacterStream() throws SQLException {
try {
debugCodeCall("setCharacterStream");
checkEditable();
state = State.SET_CALLED;
return setCharacterStreamImpl();
} catch (Exception e) {
throw logAndConvert(e);
}
}
@SuppressWarnings("unchecked")
@Override
public <T extends Result> T setResult(Class<T> resultClass) throws SQLException {
try {
if (isDebugEnabled()) {
debugCodeCall(
"getSource(" + (resultClass != null ? resultClass.getSimpleName() + ".class" : "null") + ')');
}
checkEditable();
if (resultClass == null || resultClass == DOMResult.class) {
domResult = new DOMResult();
state = State.SET_CALLED;
return (T) domResult;
} else if (resultClass == SAXResult.class) {
SAXTransformerFactory transformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
TransformerHandler transformerHandler = transformerFactory.newTransformerHandler();
Writer writer = setCharacterStreamImpl();
transformerHandler.setResult(new StreamResult(writer));
SAXResult saxResult = new SAXResult(transformerHandler);
closable = writer;
state = State.SET_CALLED;
return (T) saxResult;
} else if (resultClass == StAXResult.class) {
XMLOutputFactory xof = XMLOutputFactory.newInstance();
Writer writer = setCharacterStreamImpl();
StAXResult staxResult = new StAXResult(xof.createXMLStreamWriter(writer));
closable = writer;
state = State.SET_CALLED;
return (T) staxResult;
} else if (StreamResult.class.equals(resultClass)) {
Writer writer = setCharacterStreamImpl();
StreamResult streamResult = new StreamResult(writer);
closable = writer;
state = State.SET_CALLED;
return (T) streamResult;
}
throw unsupported(resultClass.getName());
} catch (Exception e) {
throw logAndConvert(e);
}
}
@Override
public void setString(String value) throws SQLException {
try {
if (isDebugEnabled()) {
debugCodeCall("getSource", value);
}
checkEditable();
completeWrite(conn.createClob(new StringReader(value), -1));
} catch (Exception e) {
throw logAndConvert(e);
}
}
}
...@@ -93,12 +93,17 @@ public class TraceObject { ...@@ -93,12 +93,17 @@ public class TraceObject {
*/ */
protected static final int ARRAY = 16; protected static final int ARRAY = 16;
private static final int LAST = ARRAY + 1; /**
* The trace type id for SQLXML objects.
*/
protected static final int SQLXML = 17;
private static final int LAST = SQLXML + 1;
private static final AtomicIntegerArray ID = new AtomicIntegerArray(LAST); private static final AtomicIntegerArray ID = new AtomicIntegerArray(LAST);
private static final String[] PREFIX = { "call", "conn", "dbMeta", "prep", private static final String[] PREFIX = { "call", "conn", "dbMeta", "prep",
"rs", "rsMeta", "sp", "ex", "stat", "blob", "clob", "pMeta", "ds", "rs", "rsMeta", "sp", "ex", "stat", "blob", "clob", "pMeta", "ds",
"xads", "xares", "xid", "ar" }; "xads", "xares", "xid", "ar", "sqlxml" };
/** /**
* The trace module used by this object. * The trace module used by this object.
......
...@@ -154,9 +154,9 @@ public class CreateCluster extends Tool { ...@@ -154,9 +154,9 @@ public class CreateCluster extends Tool {
} }
private static Future<?> startWriter(final PipedReader pipeReader, private static Future<?> startWriter(final PipedReader pipeReader,
final Statement statSource) { final Statement statSource) throws IOException {
final ExecutorService thread = Executors.newFixedThreadPool(1); final ExecutorService thread = Executors.newFixedThreadPool(1);
final PipedWriter pipeWriter = new PipedWriter(pipeReader);
// Since exceptions cannot be thrown across thread boundaries, return // Since exceptions cannot be thrown across thread boundaries, return
// the task's future so we can check manually // the task's future so we can check manually
Future<?> threadFuture = thread.submit(new Runnable() { Future<?> threadFuture = thread.submit(new Runnable() {
...@@ -167,10 +167,10 @@ public class CreateCluster extends Tool { ...@@ -167,10 +167,10 @@ public class CreateCluster extends Tool {
// - if the pipe is broken, unconnected, closed, or an I/O error // - if the pipe is broken, unconnected, closed, or an I/O error
// occurs. The reader's IOException will then trigger the // occurs. The reader's IOException will then trigger the
// finally{} that releases exclusive mode on the source DB. // finally{} that releases exclusive mode on the source DB.
try (final PipedWriter pipeWriter = new PipedWriter(pipeReader); try (PipedWriter writer = pipeWriter;
final ResultSet rs = statSource.executeQuery("SCRIPT")) { final ResultSet rs = statSource.executeQuery("SCRIPT")) {
while (rs.next()) { while (rs.next()) {
pipeWriter.write(rs.getString(1) + "\n"); writer.write(rs.getString(1) + "\n");
} }
} catch (SQLException | IOException ex) { } catch (SQLException | IOException ex) {
throw new IllegalStateException("Producing script from the source DB is failing.", ex); throw new IllegalStateException("Producing script from the source DB is failing.", ex);
......
...@@ -24,6 +24,7 @@ import java.sql.Types; ...@@ -24,6 +24,7 @@ import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.TimestampWithTimeZone; import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.Mode; import org.h2.engine.Mode;
...@@ -33,6 +34,7 @@ import org.h2.jdbc.JdbcArray; ...@@ -33,6 +34,7 @@ import org.h2.jdbc.JdbcArray;
import org.h2.jdbc.JdbcBlob; import org.h2.jdbc.JdbcBlob;
import org.h2.jdbc.JdbcClob; import org.h2.jdbc.JdbcClob;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcLob;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
...@@ -1118,6 +1120,15 @@ public class DataType { ...@@ -1118,6 +1120,15 @@ public class DataType {
} catch (SQLException e) { } catch (SQLException e) {
throw DbException.convert(e); throw DbException.convert(e);
} }
} else if (x instanceof java.sql.SQLXML) {
try {
java.sql.SQLXML clob = (java.sql.SQLXML) x;
Reader r = new BufferedReader(clob.getCharacterStream());
return session.getDataHandler().getLobStorage().
createClob(r, -1);
} catch (SQLException e) {
throw DbException.convert(e);
}
} else if (x instanceof java.sql.Array) { } else if (x instanceof java.sql.Array) {
java.sql.Array array = (java.sql.Array) x; java.sql.Array array = (java.sql.Array) x;
try { try {
...@@ -1365,9 +1376,9 @@ public class DataType { ...@@ -1365,9 +1376,9 @@ public class DataType {
public static Object convertTo(JdbcConnection conn, Value v, public static Object convertTo(JdbcConnection conn, Value v,
Class<?> paramClass) { Class<?> paramClass) {
if (paramClass == Blob.class) { 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) { } 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) { } else if (paramClass == Array.class) {
return new JdbcArray(conn, v, 0); return new JdbcArray(conn, v, 0);
} }
......
...@@ -21,7 +21,10 @@ import org.h2.util.Utils; ...@@ -21,7 +21,10 @@ import org.h2.util.Utils;
*/ */
public class ValueBytes extends Value { 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. * The value.
......
...@@ -18,7 +18,11 @@ import org.h2.util.StringUtils; ...@@ -18,7 +18,11 @@ import org.h2.util.StringUtils;
*/ */
public class ValueString extends Value { 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. * The string data.
......
...@@ -102,6 +102,7 @@ import org.h2.test.jdbc.TestMetaData; ...@@ -102,6 +102,7 @@ import org.h2.test.jdbc.TestMetaData;
import org.h2.test.jdbc.TestNativeSQL; import org.h2.test.jdbc.TestNativeSQL;
import org.h2.test.jdbc.TestPreparedStatement; import org.h2.test.jdbc.TestPreparedStatement;
import org.h2.test.jdbc.TestResultSet; import org.h2.test.jdbc.TestResultSet;
import org.h2.test.jdbc.TestSQLXML;
import org.h2.test.jdbc.TestStatement; import org.h2.test.jdbc.TestStatement;
import org.h2.test.jdbc.TestTransactionIsolation; import org.h2.test.jdbc.TestTransactionIsolation;
import org.h2.test.jdbc.TestUpdatableResultSet; import org.h2.test.jdbc.TestUpdatableResultSet;
...@@ -797,6 +798,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -797,6 +798,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestJavaObject()); addTest(new TestJavaObject());
addTest(new TestLimitUpdates()); addTest(new TestLimitUpdates());
addTest(new TestLobApi()); addTest(new TestLobApi());
addTest(new TestSQLXML());
addTest(new TestManyJdbcObjects()); addTest(new TestManyJdbcObjects());
addTest(new TestMetaData()); addTest(new TestMetaData());
addTest(new TestNativeSQL()); addTest(new TestNativeSQL());
......
...@@ -111,8 +111,6 @@ public class TestCallableStatement extends TestDb { ...@@ -111,8 +111,6 @@ public class TestCallableStatement extends TestDb {
setRef(1, (Ref) null); setRef(1, (Ref) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, call). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, call).
setRowId(1, (RowId) null); setRowId(1, (RowId) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, call).
setSQLXML(1, (SQLXML) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, call). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, call).
setURL("a", (URL) null); setURL("a", (URL) null);
......
...@@ -81,7 +81,7 @@ public class TestLobApi extends TestDb { ...@@ -81,7 +81,7 @@ public class TestLobApi extends TestDb {
assertEquals("x", new String(data, StandardCharsets.UTF_8)); assertEquals("x", new String(data, StandardCharsets.UTF_8));
assertTrue(clob.toString().endsWith("'x'")); assertTrue(clob.toString().endsWith("'x'"));
clob.free(); clob.free();
assertTrue(clob.toString().endsWith("null")); assertTrue(clob.toString().endsWith("<closed>"));
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, clob). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, clob).
truncate(0); truncate(0);
...@@ -101,7 +101,7 @@ public class TestLobApi extends TestDb { ...@@ -101,7 +101,7 @@ public class TestLobApi extends TestDb {
position((Blob) null, 0); position((Blob) null, 0);
assertTrue(blob.toString().endsWith("X'00'")); assertTrue(blob.toString().endsWith("X'00'"));
blob.free(); blob.free();
assertTrue(blob.toString().endsWith("null")); assertTrue(blob.toString().endsWith("<closed>"));
stat.execute("drop table test"); stat.execute("drop table test");
conn.close(); conn.close();
......
...@@ -153,8 +153,6 @@ public class TestPreparedStatement extends TestDb { ...@@ -153,8 +153,6 @@ public class TestPreparedStatement extends TestDb {
ParameterMetaData meta = prep.getParameterMetaData(); ParameterMetaData meta = prep.getParameterMetaData();
assertTrue(meta.toString(), meta.toString().endsWith("parameterCount=1")); assertTrue(meta.toString(), meta.toString().endsWith("parameterCount=1"));
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, conn).
createSQLXML();
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, conn). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, conn).
createStruct("Integer", new Object[0]); createStruct("Integer", new Object[0]);
} }
......
...@@ -27,7 +27,6 @@ import java.sql.ResultSet; ...@@ -27,7 +27,6 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.RowId; import java.sql.RowId;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
...@@ -162,10 +161,6 @@ public class TestResultSet extends TestDb { ...@@ -162,10 +161,6 @@ public class TestResultSet extends TestDb {
getRowId(1); getRowId(1);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
getRowId("x"); getRowId("x");
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
getSQLXML(1);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
getSQLXML("x");
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
updateRef(1, (Ref) null); updateRef(1, (Ref) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
...@@ -178,14 +173,6 @@ public class TestResultSet extends TestDb { ...@@ -178,14 +173,6 @@ public class TestResultSet extends TestDb {
updateRowId(1, (RowId) null); updateRowId(1, (RowId) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
updateRowId("x", (RowId) null); 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).
updateSQLXML("x", (SQLXML) null);
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
getCursorName(); getCursorName();
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs). assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, rs).
...@@ -208,8 +195,9 @@ public class TestResultSet extends TestDb { ...@@ -208,8 +195,9 @@ public class TestResultSet extends TestDb {
PreparedStatement prep = conn.prepareStatement("select * from test", PreparedStatement prep = conn.prepareStatement("select * from test",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
int idx = 1;
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 1); rs.updateInt(1, idx++);
rs.insertRow(); rs.insertRow();
rs.close(); rs.close();
rs = stat.executeQuery("select * from test"); rs = stat.executeQuery("select * from test");
...@@ -230,12 +218,12 @@ public class TestResultSet extends TestDb { ...@@ -230,12 +218,12 @@ public class TestResultSet extends TestDb {
rs = prep.executeQuery(); rs = prep.executeQuery();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 2); rs.updateInt(1, idx++);
rs.updateNString(2, "Hello"); rs.updateNString(2, "Hello");
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 3); rs.updateInt(1, idx++);
rs.updateNString("data", "Hello"); rs.updateNString("data", "Hello");
rs.insertRow(); rs.insertRow();
...@@ -243,7 +231,7 @@ public class TestResultSet extends TestDb { ...@@ -243,7 +231,7 @@ public class TestResultSet extends TestDb {
Writer w; Writer w;
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 4); rs.updateInt(1, idx++);
c = conn.createClob(); c = conn.createClob();
w = c.setCharacterStream(1); w = c.setCharacterStream(1);
w.write("Hello"); w.write("Hello");
...@@ -252,7 +240,7 @@ public class TestResultSet extends TestDb { ...@@ -252,7 +240,7 @@ public class TestResultSet extends TestDb {
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 5); rs.updateInt(1, idx++);
c = conn.createClob(); c = conn.createClob();
w = c.setCharacterStream(1); w = c.setCharacterStream(1);
w.write("Hello"); w.write("Hello");
...@@ -260,48 +248,70 @@ public class TestResultSet extends TestDb { ...@@ -260,48 +248,70 @@ public class TestResultSet extends TestDb {
rs.updateClob("data", c); rs.updateClob("data", c);
rs.insertRow(); rs.insertRow();
NClob nc;
rs.moveToInsertRow();
rs.updateInt(1, idx++);
nc = conn.createNClob();
w = nc.setCharacterStream(1);
w.write("Hello");
w.close();
rs.updateNClob(2, nc);
rs.insertRow();
rs.moveToInsertRow();
rs.updateInt(1, idx++);
nc = conn.createNClob();
w = nc.setCharacterStream(1);
w.write("Hello");
w.close();
rs.updateNClob("data", nc);
rs.insertRow();
InputStream in; InputStream in;
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 6); rs.updateInt(1, idx++);
in = new ByteArrayInputStream("Hello".getBytes(StandardCharsets.UTF_8)); in = new ByteArrayInputStream("Hello".getBytes(StandardCharsets.UTF_8));
rs.updateAsciiStream(2, in); rs.updateAsciiStream(2, in);
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 7); rs.updateInt(1, idx++);
in = new ByteArrayInputStream("Hello".getBytes(StandardCharsets.UTF_8)); in = new ByteArrayInputStream("Hello".getBytes(StandardCharsets.UTF_8));
rs.updateAsciiStream("data", in); rs.updateAsciiStream("data", in);
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 8); rs.updateInt(1, idx++);
in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8)); in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8));
rs.updateAsciiStream(2, in, 5); rs.updateAsciiStream(2, in, 5);
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 9); rs.updateInt(1, idx++);
in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8)); in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8));
rs.updateAsciiStream("data", in, 5); rs.updateAsciiStream("data", in, 5);
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 10); rs.updateInt(1, idx++);
in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8)); in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8));
rs.updateAsciiStream(2, in, 5L); rs.updateAsciiStream(2, in, 5L);
rs.insertRow(); rs.insertRow();
rs.moveToInsertRow(); rs.moveToInsertRow();
rs.updateInt(1, 11); rs.updateInt(1, idx++);
in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8)); in = new ByteArrayInputStream("Hello-".getBytes(StandardCharsets.UTF_8));
rs.updateAsciiStream("data", in, 5L); rs.updateAsciiStream("data", in, 5L);
rs.insertRow(); rs.insertRow();
rs = stat.executeQuery("select * from test"); rs = stat.executeQuery("select * from test");
while (rs.next()) { for (int i = 1; i < idx; i++) {
assertTrue(rs.next());
assertEquals("Hello", rs.getString(2)); assertEquals("Hello", rs.getString(2));
} }
assertFalse(rs.next());
stat.execute("drop table test"); stat.execute("drop table test");
} }
......
/*
* 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.test.jdbc;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Statement;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXResult;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.h2.api.ErrorCode;
import org.h2.jdbc.JdbcConnection;
import org.h2.test.TestBase;
import org.h2.test.TestDb;
import org.h2.util.IOUtils;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Test the SQLXML implementation.
*/
public class TestSQLXML extends TestDb {
private static final String XML = "<xml a=\"v\">Text</xml>";
private JdbcConnection conn;
private Statement stat;
/**
* Run just this test.
*
* @param a
* ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws Exception {
deleteDb(getTestName());
conn = (JdbcConnection) getConnection(getTestName());
stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, X CLOB)");
stat.execute("INSERT INTO TEST VALUES (1, NULL)");
testGetters();
testSetters();
conn.close();
deleteDb(getTestName());
}
private void testGetters() throws SQLException, IOException, XMLStreamException {
ResultSet rs = stat.executeQuery("SELECT * FROM TEST");
assertTrue(rs.next());
assertNull(rs.getSQLXML(2));
assertNull(rs.getSQLXML("X"));
assertEquals(1, stat.executeUpdate("UPDATE TEST SET X = '" + XML + '\''));
rs = stat.executeQuery("SELECT * FROM TEST");
assertTrue(rs.next());
// ResultSet.getObject()
SQLXML sqlxml = rs.getObject(2, SQLXML.class);
assertEquals(XML, sqlxml.getString());
sqlxml = rs.getSQLXML(2);
// getBinaryStream()
assertEquals(XML, IOUtils.readStringAndClose(IOUtils.getReader(sqlxml.getBinaryStream()), -1));
// getCharacterStream()
assertEquals(XML, IOUtils.readStringAndClose(sqlxml.getCharacterStream(), -1));
// getString()
assertEquals(XML, sqlxml.getString());
// DOMSource
DOMSource domSource = sqlxml.getSource(DOMSource.class);
Node n = domSource.getNode().getFirstChild();
assertEquals("xml", n.getNodeName());
assertEquals("v", n.getAttributes().getNamedItem("a").getNodeValue());
assertEquals("Text", n.getFirstChild().getNodeValue());
// SAXSource
SAXSource saxSource = sqlxml.getSource(SAXSource.class);
assertEquals(XML,
IOUtils.readStringAndClose(IOUtils.getReader(saxSource.getInputSource().getByteStream()), -1));
// StAXSource
StAXSource staxSource = sqlxml.getSource(StAXSource.class);
XMLStreamReader stxReader = staxSource.getXMLStreamReader();
assertEquals(XMLStreamReader.START_DOCUMENT, stxReader.getEventType());
assertEquals(XMLStreamReader.START_ELEMENT, stxReader.next());
assertEquals("xml", stxReader.getLocalName());
assertEquals("a", stxReader.getAttributeLocalName(0));
assertEquals("v", stxReader.getAttributeValue(0));
assertEquals(XMLStreamReader.CHARACTERS, stxReader.next());
assertEquals("Text", stxReader.getText());
assertEquals(XMLStreamReader.END_ELEMENT, stxReader.next());
assertEquals(XMLStreamReader.END_DOCUMENT, stxReader.next());
// StreamSource
StreamSource streamSource = sqlxml.getSource(StreamSource.class);
assertEquals(XML, IOUtils.readStringAndClose(IOUtils.getReader(streamSource.getInputStream()), -1));
// something illegal
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, sqlxml).getSource(Source.class);
}
private void testSetters() throws SQLException, IOException, SAXException, ParserConfigurationException,
TransformerConfigurationException, TransformerException {
// setBinaryStream()
SQLXML sqlxml = conn.createSQLXML();
try (OutputStream out = sqlxml.setBinaryStream()) {
out.write(XML.getBytes(StandardCharsets.UTF_8));
}
testSettersImpl(sqlxml);
// setCharacterStream()
sqlxml = conn.createSQLXML();
try (Writer out = sqlxml.setCharacterStream()) {
out.write(XML);
}
testSettersImpl(sqlxml);
// setString()
sqlxml = conn.createSQLXML();
sqlxml.setString(XML);
testSettersImpl(sqlxml);
TransformerFactory tf = TransformerFactory.newInstance();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DOMSource domSource = new DOMSource(dbf.newDocumentBuilder().parse(new InputSource(new StringReader(XML))));
// DOMResult
sqlxml = conn.createSQLXML();
tf.newTransformer().transform(domSource, sqlxml.setResult(DOMResult.class));
testSettersImpl(sqlxml);
// SAXResult
sqlxml = conn.createSQLXML();
tf.newTransformer().transform(domSource, sqlxml.setResult(SAXResult.class));
testSettersImpl(sqlxml);
// StAXResult
sqlxml = conn.createSQLXML();
tf.newTransformer().transform(domSource, sqlxml.setResult(StAXResult.class));
testSettersImpl(sqlxml);
// StreamResult
sqlxml = conn.createSQLXML();
tf.newTransformer().transform(domSource, sqlxml.setResult(StreamResult.class));
testSettersImpl(sqlxml);
// something illegal
assertThrows(ErrorCode.FEATURE_NOT_SUPPORTED_1, sqlxml).setResult(Result.class);
// null
testSettersImpl(null);
}
private void assertXML(String actual) {
if (actual.startsWith("<?")) {
actual = actual.substring(actual.indexOf("?>") + 2);
}
assertEquals(XML, actual);
}
private void testSettersImplAssert(SQLXML sqlxml) throws SQLException {
ResultSet rs = stat.executeQuery("SELECT X FROM TEST");
assertTrue(rs.next());
SQLXML v = rs.getSQLXML(1);
if (sqlxml != null) {
assertXML(v.getString());
} else {
assertNull(v);
}
}
void testSettersImpl(SQLXML sqlxml) throws SQLException {
PreparedStatement prep = conn.prepareStatement("UPDATE TEST SET X = ?");
prep.setSQLXML(1, sqlxml);
assertEquals(1, prep.executeUpdate());
testSettersImplAssert(sqlxml);
prep.setObject(1, sqlxml);
assertEquals(1, prep.executeUpdate());
testSettersImplAssert(sqlxml);
Statement st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = st.executeQuery("SELECT * FROM TEST FOR UPDATE");
assertTrue(rs.next());
rs.updateSQLXML(2, sqlxml);
rs.updateRow();
testSettersImplAssert(sqlxml);
rs = st.executeQuery("SELECT * FROM TEST FOR UPDATE");
assertTrue(rs.next());
rs.updateSQLXML("X", sqlxml);
rs.updateRow();
testSettersImplAssert(sqlxml);
rs = st.executeQuery("SELECT * FROM TEST FOR UPDATE");
assertTrue(rs.next());
rs.updateObject(2, sqlxml);
rs.updateRow();
testSettersImplAssert(sqlxml);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论