HHH-18806 attempt to make handling of Clob/NClob more robust
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
1ef22c01f3
commit
2d9f58ae4b
|
@ -3777,12 +3777,12 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
|
|||
}
|
||||
|
||||
/**
|
||||
* Should BLOB, CLOB, and NCLOB be created solely using respectively
|
||||
* {@link Connection#createBlob()}, {@link Connection#createClob()},
|
||||
* and {@link Connection#createNClob()}.
|
||||
* Should {@link Blob}, {@link Clob}, and {@link NClob} be created solely
|
||||
* using {@link Connection#createBlob()}, {@link Connection#createClob()},
|
||||
* and {@link Connection#createNClob()}, instead of allowing the use of
|
||||
* our own implementations.
|
||||
*
|
||||
* @return True if BLOB, CLOB, and NCLOB should be created using JDBC
|
||||
* {@link Connection}.
|
||||
* @return True if these types should be instantiated using {@link Connection}.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.hibernate.type.NullType;
|
|||
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.TinyIntAsSmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
@ -213,7 +214,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||
jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcType.CLOB_BINDING );
|
||||
jdbcTypeRegistry.addDescriptor( Types.NCLOB, ClobJdbcType.CLOB_BINDING );
|
||||
jdbcTypeRegistry.addDescriptor( Types.NCLOB, NClobJdbcType.NCLOB_BINDING );
|
||||
}
|
||||
else {
|
||||
// jConnect driver only conditionally supports getClob/getNClob depending on a server setting. See
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.NClob;
|
||||
|
||||
/**
|
||||
* Convenient base class for proxy-based LobCreator for handling wrapping.
|
||||
* Convenient base class for proxy-based {@link LobCreator} for handling wrapping.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -20,16 +22,28 @@ public abstract class AbstractLobCreator implements LobCreator {
|
|||
|
||||
@Override
|
||||
public Clob wrap(Clob clob) {
|
||||
if ( clob instanceof NClob ) {
|
||||
return wrap( (NClob) clob );
|
||||
}
|
||||
else {
|
||||
return SerializableClobProxy.generateProxy( clob );
|
||||
}
|
||||
return clob instanceof NClob nclob
|
||||
? wrap( nclob )
|
||||
: SerializableClobProxy.generateProxy( clob );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob wrap(NClob nclob) {
|
||||
return SerializableNClobProxy.generateProxy( nclob );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob(Blob blob) {
|
||||
return blob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clob createClob(Clob clob) {
|
||||
return clob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob(NClob clob) {
|
||||
return clob;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.sql.Blob;
|
||||
|
||||
/**
|
||||
* Wraps a binary stream to also provide the length which is needed when binding.
|
||||
|
@ -37,4 +38,12 @@ public interface BinaryStream {
|
|||
* Release any underlying resources.
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Use the given {@link LobCreator} to create a {@link Blob}
|
||||
* with the same data as this binary stream.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
Blob asBlob(LobCreator lobCreator);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ import java.sql.Blob;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.StreamBackedBinaryStream;
|
||||
import org.hibernate.type.descriptor.java.DataHelper;
|
||||
|
||||
/**
|
||||
|
@ -45,7 +46,7 @@ public final class BlobProxy implements Blob, BlobImplementer {
|
|||
* @see #generateProxy(byte[])
|
||||
*/
|
||||
private BlobProxy(byte[] bytes) {
|
||||
binaryStream = new BinaryStreamImpl( bytes );
|
||||
binaryStream = new ArrayBackedBinaryStream( bytes );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,45 +180,6 @@ public final class BlobProxy implements Blob, BlobImplementer {
|
|||
return DataHelper.subStream( getStream(), start-1, intLength );
|
||||
}
|
||||
|
||||
private static class StreamBackedBinaryStream implements BinaryStream {
|
||||
|
||||
private final InputStream stream;
|
||||
private final long length;
|
||||
private byte[] bytes;
|
||||
|
||||
private StreamBackedBinaryStream(InputStream stream, long length) {
|
||||
this.stream = stream;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
if ( bytes == null ) {
|
||||
bytes = DataHelper.extractBytes( stream );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static UnsupportedOperationException notSupported() {
|
||||
return new UnsupportedOperationException( "Blob may not be manipulated from creating session" );
|
||||
}
|
||||
|
|
|
@ -100,4 +100,8 @@ public interface LobCreator {
|
|||
* environments, also castable to java.sql.NClob
|
||||
*/
|
||||
NClob createNClob(Reader reader, long length);
|
||||
|
||||
Blob createBlob(Blob clob);
|
||||
Clob createClob(Clob clob);
|
||||
NClob createNClob(NClob clob);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.hibernate.engine.jdbc.NClobProxy;
|
|||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
|
||||
/**
|
||||
* LobCreator which can use {@link Connection#createBlob} and {@link Connection#createClob},
|
||||
* {@link LobCreator} which can use {@link Connection#createBlob} and {@link Connection#createClob},
|
||||
* but {@link java.sql.NClob} references are created locally.
|
||||
*
|
||||
* @see NClobProxy
|
||||
|
@ -40,9 +40,11 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
|
|||
public static final LobCreationContext.Callback<Clob> CREATE_CLOB_CALLBACK = Connection::createClob;
|
||||
|
||||
protected final LobCreationContext lobCreationContext;
|
||||
protected final boolean useConnectionToCreateLob;
|
||||
|
||||
public BlobAndClobCreator(LobCreationContext lobCreationContext) {
|
||||
public BlobAndClobCreator(LobCreationContext lobCreationContext, boolean useConnectionToCreateLob) {
|
||||
this.lobCreationContext = lobCreationContext;
|
||||
this.useConnectionToCreateLob = useConnectionToCreateLob;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,8 +70,9 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
|
|||
|
||||
@Override
|
||||
public Blob createBlob(InputStream stream, long length) {
|
||||
// IMPL NOTE : it is inefficient to use JDBC LOB locator creation to create a LOB
|
||||
// backed by a given stream. So just wrap the stream (which is what the NonContextualLobCreator does).
|
||||
// IMPL NOTE: it's inefficient to use JDBC LOB locator creation to
|
||||
// create a LOB backed by a given stream. So just wrap the stream
|
||||
// (which is what the NonContextualLobCreator does).
|
||||
return NonContextualLobCreator.INSTANCE.createBlob( stream, length );
|
||||
}
|
||||
|
||||
|
@ -96,8 +99,9 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
|
|||
|
||||
@Override
|
||||
public Clob createClob(Reader reader, long length) {
|
||||
// IMPL NOTE : it is inefficient to use JDBC LOB locator creation to create a LOB
|
||||
// backed by a given stream. So just wrap the stream (which is what the NonContextualLobCreator does).
|
||||
// IMPL NOTE: it's inefficient to use JDBC LOB locator creation to
|
||||
// create a LOB backed by a given stream. So just wrap the stream
|
||||
// (which is what the NonContextualLobCreator does).
|
||||
return NonContextualLobCreator.INSTANCE.createClob( reader, length );
|
||||
}
|
||||
|
||||
|
@ -110,4 +114,40 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
|
|||
public NClob createNClob(Reader reader, long length) {
|
||||
return NonContextualLobCreator.INSTANCE.createNClob( reader, length );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob(Blob blob) {
|
||||
try {
|
||||
return useConnectionToCreateLob
|
||||
? createBlob( blob.getBytes( 1, (int) blob.length() ) )
|
||||
: blob;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new JDBCException( "Could not create JDBC Clob", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clob createClob(Clob clob) {
|
||||
try {
|
||||
return useConnectionToCreateLob
|
||||
? createClob( clob.getSubString( 1, (int) clob.length() ) )
|
||||
: clob;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new JDBCException( "Could not create JDBC Clob", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob(NClob clob) {
|
||||
try {
|
||||
return useConnectionToCreateLob
|
||||
? createNClob( clob.getSubString( 1, (int) clob.length() ) )
|
||||
: clob;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new JDBCException( "Could not create JDBC Clob", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl.makeLobCreatorBuilder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -100,7 +102,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
|
||||
this.qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport );
|
||||
|
||||
this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder();
|
||||
this.lobCreatorBuilder = makeLobCreatorBuilder( dialect );
|
||||
}
|
||||
|
||||
private IdentifierHelperBuilder identifierHelperBuilder(
|
||||
|
@ -201,7 +203,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
databaseMetaData
|
||||
);
|
||||
|
||||
this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder();
|
||||
this.lobCreatorBuilder = makeLobCreatorBuilder( dialect );
|
||||
}
|
||||
|
||||
private IdentifierHelper identifierHelper(DatabaseMetaData databaseMetaData, Dialect dialect) {
|
||||
|
|
|
@ -25,9 +25,11 @@ import static org.hibernate.engine.jdbc.env.internal.LobCreationLogging.LOB_MESS
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
||||
private final boolean useConnectionToCreateLob;
|
||||
private final EnumSet<LobTypes> supportedContextualLobTypes;
|
||||
|
||||
public LobCreatorBuilderImpl(EnumSet<LobTypes> supportedContextualLobTypes) {
|
||||
public LobCreatorBuilderImpl(boolean useConnectionToCreateLob, EnumSet<LobTypes> supportedContextualLobTypes) {
|
||||
this.useConnectionToCreateLob = useConnectionToCreateLob;
|
||||
this.supportedContextualLobTypes = supportedContextualLobTypes;
|
||||
}
|
||||
|
||||
|
@ -46,13 +48,8 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
|||
Dialect dialect,
|
||||
Map<String,Object> configValues,
|
||||
Connection jdbcConnection) {
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
configValues,
|
||||
jdbcConnection
|
||||
);
|
||||
|
||||
return new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
return new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(),
|
||||
getSupportedContextualLobTypes( dialect, configValues, jdbcConnection ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,9 +57,9 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
|||
*
|
||||
* @return Appropriate LobCreatorBuilder
|
||||
*/
|
||||
public static LobCreatorBuilderImpl makeLobCreatorBuilder() {
|
||||
public static LobCreatorBuilderImpl makeLobCreatorBuilder(Dialect dialect) {
|
||||
LOB_MESSAGE_LOGGER.disablingContextualLOBCreationSinceConnectionNull();
|
||||
return new LobCreatorBuilderImpl( NONE );
|
||||
return new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(), NONE );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,17 +73,18 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
|||
if ( supportedContextualLobTypes.isEmpty() ) {
|
||||
return NonContextualLobCreator.INSTANCE;
|
||||
}
|
||||
|
||||
if ( supportedContextualLobTypes.contains( LobTypes.BLOB )
|
||||
else if ( supportedContextualLobTypes.contains( LobTypes.BLOB )
|
||||
&& supportedContextualLobTypes.contains( LobTypes.CLOB ) ){
|
||||
if ( !supportedContextualLobTypes.contains( LobTypes.NCLOB ) ) {
|
||||
return new BlobAndClobCreator( lobCreationContext );
|
||||
return new BlobAndClobCreator( lobCreationContext, useConnectionToCreateLob );
|
||||
}
|
||||
else {
|
||||
return new StandardLobCreator( lobCreationContext, useConnectionToCreateLob );
|
||||
}
|
||||
|
||||
return new StandardLobCreator( lobCreationContext );
|
||||
}
|
||||
|
||||
LOB_LOGGER.debug( "Unexpected condition resolving type of LobCreator to use. Falling back to NonContextualLobCreator" );
|
||||
return NonContextualLobCreator.INSTANCE;
|
||||
else {
|
||||
LOB_LOGGER.debug( "Unexpected condition resolving type of LobCreator to use. Falling back to NonContextualLobCreator" );
|
||||
return NonContextualLobCreator.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ public class StandardLobCreator extends BlobAndClobCreator {
|
|||
*/
|
||||
public static final LobCreationContext.Callback<NClob> CREATE_NCLOB_CALLBACK = Connection::createNClob;
|
||||
|
||||
public StandardLobCreator(LobCreationContext lobCreationContext) {
|
||||
super( lobCreationContext );
|
||||
public StandardLobCreator(LobCreationContext lobCreationContext, boolean useConnectionToCreateLob) {
|
||||
super( lobCreationContext, useConnectionToCreateLob );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,43 +4,53 @@
|
|||
*/
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import java.sql.Blob;
|
||||
|
||||
/**
|
||||
* Implementation of {@link BinaryStream}
|
||||
* Implementation of {@link BinaryStream} backed by a {@code byte[]} array.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public final class BinaryStreamImpl extends ByteArrayInputStream implements BinaryStream {
|
||||
public class ArrayBackedBinaryStream extends ByteArrayInputStream implements BinaryStream {
|
||||
private final int length;
|
||||
|
||||
/**
|
||||
* Constructs a BinaryStreamImpl
|
||||
* Constructs a ArrayBackedBinaryStream
|
||||
*
|
||||
* @param bytes The bytes to use backing the stream
|
||||
*/
|
||||
public BinaryStreamImpl(byte[] bytes) {
|
||||
public ArrayBackedBinaryStream(byte[] bytes) {
|
||||
super( bytes );
|
||||
this.length = bytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
// from ByteArrayInputStream
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob asBlob(LobCreator lobCreator) {
|
||||
return lobCreator.createBlob( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.Blob;
|
||||
|
||||
/**
|
||||
* Implementation of {@link BinaryStream} backed by an {@link InputStream}.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public class StreamBackedBinaryStream implements BinaryStream {
|
||||
|
||||
private final InputStream stream;
|
||||
private final long length;
|
||||
private byte[] bytes;
|
||||
|
||||
public StreamBackedBinaryStream(InputStream stream, long length) {
|
||||
this.stream = stream;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
if ( bytes == null ) {
|
||||
try {
|
||||
bytes = stream.readAllBytes();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new HibernateException( "IOException occurred reading a binary value", e );
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob asBlob(LobCreator lobCreator) {
|
||||
return lobCreator.createBlob( stream, length );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
|
@ -264,7 +264,7 @@ public class ArrayJavaType<T> extends AbstractArrayJavaType<T[], T> {
|
|||
}
|
||||
else if ( type == BinaryStream.class ) {
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( toBytes( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( toBytes( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -16,12 +16,15 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BlobImplementer;
|
||||
import org.hibernate.engine.jdbc.BlobProxy;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.internal.StreamBackedBinaryStream;
|
||||
import org.hibernate.engine.jdbc.WrappedBlob;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
import static org.hibernate.type.descriptor.java.DataHelper.extractBytes;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Blob} handling.
|
||||
* <p>
|
||||
|
@ -72,7 +75,7 @@ public class BlobJavaType extends AbstractClassJavaType<Blob> {
|
|||
public String toString(Blob value) {
|
||||
final byte[] bytes;
|
||||
try {
|
||||
bytes = DataHelper.extractBytes( value.getBinaryStream() );
|
||||
bytes = extractBytes( value.getBinaryStream() );
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new HibernateException( "Unable to access blob stream", e );
|
||||
|
@ -109,15 +112,12 @@ public class BlobJavaType extends AbstractClassJavaType<Blob> {
|
|||
}
|
||||
|
||||
try {
|
||||
if ( BinaryStream.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof BlobImplementer blobImplementer) {
|
||||
// if the incoming Blob is a wrapper, just pass along its BinaryStream
|
||||
return (X) blobImplementer.getUnderlyingStream();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a BinaryStream...
|
||||
return (X) new BinaryStreamImpl( DataHelper.extractBytes( value.getBinaryStream() ) );
|
||||
if ( Blob.class.isAssignableFrom( type ) ) {
|
||||
Blob blob = value;
|
||||
if ( blob instanceof WrappedBlob wrappedBlob ) {
|
||||
blob = wrappedBlob.getWrappedBlob();
|
||||
}
|
||||
return (X) options.getLobCreator().createBlob( blob );
|
||||
}
|
||||
else if ( byte[].class.isAssignableFrom( type )) {
|
||||
if (value instanceof BlobImplementer blobImplementer) {
|
||||
|
@ -125,12 +125,32 @@ public class BlobJavaType extends AbstractClassJavaType<Blob> {
|
|||
return (X) blobImplementer.getUnderlyingStream().getBytes();
|
||||
}
|
||||
else {
|
||||
// otherwise extract the bytes from the stream manually
|
||||
return (X) DataHelper.extractBytes( value.getBinaryStream() );
|
||||
try {
|
||||
// otherwise extract the bytes from the stream manually
|
||||
return (X) value.getBinaryStream().readAllBytes();
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new HibernateException( "IOException occurred reading a binary value", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( Blob.class.isAssignableFrom( type ) ) {
|
||||
return (X) getOrCreateBlob( value, options );
|
||||
else if ( BinaryStream.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof BlobImplementer blobImplementer) {
|
||||
return (X) blobImplementer.getUnderlyingStream();
|
||||
}
|
||||
else {
|
||||
return (X) new StreamBackedBinaryStream( value.getBinaryStream(), value.length() );
|
||||
}
|
||||
}
|
||||
else if ( InputStream.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof BlobImplementer blobImplementer) {
|
||||
// if the incoming Blob is a wrapper, just pass along its BinaryStream
|
||||
return (X) blobImplementer.getUnderlyingStream().getInputStream();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a BinaryStream...
|
||||
return (X) value.getBinaryStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
|
@ -140,45 +160,32 @@ public class BlobJavaType extends AbstractClassJavaType<Blob> {
|
|||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
private Blob getOrCreateBlob(Blob value, WrapperOptions options) throws SQLException {
|
||||
if ( value instanceof WrappedBlob wrappedBlob ) {
|
||||
value = wrappedBlob.getWrappedBlob();
|
||||
}
|
||||
if ( options.getDialect().useConnectionToCreateLob() ) {
|
||||
if ( value.length() == 0 ) {
|
||||
// empty Blob
|
||||
return options.getLobCreator().createBlob( new byte[0] );
|
||||
}
|
||||
else {
|
||||
return options.getLobCreator().createBlob( value.getBytes( 1, (int) value.length() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> Blob wrap(X value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
else if ( value instanceof Blob blob ) {
|
||||
return options.getLobCreator().wrap( blob );
|
||||
}
|
||||
else if ( value instanceof byte[] bytes ) {
|
||||
return options.getLobCreator().createBlob( bytes );
|
||||
}
|
||||
else if ( value instanceof InputStream inputStream ) {
|
||||
try {
|
||||
return options.getLobCreator().createBlob( inputStream, inputStream.available() );
|
||||
else {
|
||||
final LobCreator lobCreator = options.getLobCreator();
|
||||
if ( value instanceof Blob blob ) {
|
||||
return lobCreator.wrap( blob );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
else if ( value instanceof byte[] bytes ) {
|
||||
return lobCreator.createBlob( bytes );
|
||||
}
|
||||
else if ( value instanceof BinaryStream binaryStream) {
|
||||
return binaryStream.asBlob( lobCreator );
|
||||
}
|
||||
else if ( value instanceof InputStream inputStream ) {
|
||||
// A JDBC Blob object needs to know its length, but
|
||||
// there's no way to get an accurate length from an
|
||||
// InputStream without reading the whole stream
|
||||
return lobCreator.createBlob( extractBytes( inputStream ) );
|
||||
}
|
||||
else {
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public class BooleanPrimitiveArrayJavaType extends AbstractArrayJavaType<boolean
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Arrays;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.AdjustableJdbcType;
|
||||
|
@ -99,7 +99,7 @@ public class ByteArrayJavaType extends AbstractClassJavaType<Byte[]> {
|
|||
return (X) new ByteArrayInputStream( unwrapBytes( value ) );
|
||||
}
|
||||
if ( BinaryStream.class.isAssignableFrom( type ) ) {
|
||||
return (X) new BinaryStreamImpl( unwrapBytes( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( unwrapBytes( value ) );
|
||||
}
|
||||
if ( Blob.class.isAssignableFrom( type ) ) {
|
||||
return (X) options.getLobCreator().createBlob( unwrapBytes( value ) );
|
||||
|
|
|
@ -16,13 +16,15 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.ClobImplementer;
|
||||
import org.hibernate.engine.jdbc.ClobProxy;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.WrappedClob;
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
||||
import static org.hibernate.type.descriptor.java.DataHelper.extractString;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Clob} handling.
|
||||
* <p>
|
||||
|
@ -52,7 +54,7 @@ public class ClobJavaType extends AbstractClassJavaType<Clob> {
|
|||
}
|
||||
|
||||
public String toString(Clob value) {
|
||||
return DataHelper.extractString( value );
|
||||
return extractString( value );
|
||||
}
|
||||
|
||||
public Clob fromString(CharSequence string) {
|
||||
|
@ -82,37 +84,41 @@ public class ClobJavaType extends AbstractClassJavaType<Clob> {
|
|||
}
|
||||
|
||||
try {
|
||||
if ( CharacterStream.class.isAssignableFrom( type ) ) {
|
||||
if ( Clob.class.isAssignableFrom( type ) ) {
|
||||
Clob clob = value;
|
||||
if ( clob instanceof WrappedClob wrappedClob ) {
|
||||
clob = wrappedClob.getWrappedClob();
|
||||
}
|
||||
return (X) options.getLobCreator().createClob( clob );
|
||||
}
|
||||
else if ( String.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof ClobImplementer clobImplementer) {
|
||||
// if the incoming Clob is a wrapper, just grab the string from its CharacterStream
|
||||
return (X) clobImplementer.getUnderlyingStream().asString();
|
||||
}
|
||||
else {
|
||||
// otherwise extract the bytes from the stream manually
|
||||
return (X) extractString( value.getCharacterStream() );
|
||||
}
|
||||
}
|
||||
else if ( Reader.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof ClobImplementer clobImplementer) {
|
||||
// if the incoming NClob is a wrapper, just pass along its BinaryStream
|
||||
return (X) clobImplementer.getUnderlyingStream().asReader();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a CharacterStream...
|
||||
return (X) value.getCharacterStream();
|
||||
}
|
||||
}
|
||||
else if ( CharacterStream.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof ClobImplementer clobImplementer) {
|
||||
// if the incoming Clob is a wrapper, just pass along its CharacterStream
|
||||
return (X) clobImplementer.getUnderlyingStream();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a CharacterStream...
|
||||
return (X) new CharacterStreamImpl( DataHelper.extractString( value.getCharacterStream() ) );
|
||||
}
|
||||
}
|
||||
else if ( String.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof ClobImplementer clobImplementer) {
|
||||
// if the incoming Clob is a wrapper, just grab the bytes from its BinaryStream
|
||||
return (X) clobImplementer.getUnderlyingStream().asString();
|
||||
}
|
||||
else {
|
||||
// otherwise extract the bytes from the stream manually
|
||||
return (X) DataHelper.extractString( value.getCharacterStream() );
|
||||
}
|
||||
}
|
||||
else if ( Clob.class.isAssignableFrom( type ) ) {
|
||||
return (X) getOrCreateClob( value, options );
|
||||
}
|
||||
else if ( String.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof ClobImplementer clobImplementer) {
|
||||
// if the incoming Clob is a wrapper, just get the underlying String.
|
||||
return (X) clobImplementer.getUnderlyingStream().asString();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to extract the String.
|
||||
return (X) DataHelper.extractString( value.getCharacterStream() );
|
||||
return (X) value.getCharacterStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,39 +129,28 @@ public class ClobJavaType extends AbstractClassJavaType<Clob> {
|
|||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
private Clob getOrCreateClob(Clob value, WrapperOptions options) throws SQLException {
|
||||
if ( value instanceof WrappedClob wrappedClob ) {
|
||||
value = wrappedClob.getWrappedClob();
|
||||
}
|
||||
if ( options.getDialect().useConnectionToCreateLob() ) {
|
||||
if ( value.length() == 0 ) {
|
||||
// empty Clob
|
||||
return options.getLobCreator().createClob( "" );
|
||||
}
|
||||
else {
|
||||
return options.getLobCreator().createClob( value.getSubString( 1, (int) value.length() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public <X> Clob wrap(X value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
else if ( value instanceof Clob clob ) {
|
||||
return options.getLobCreator().wrap( clob );
|
||||
else {
|
||||
final LobCreator lobCreator = options.getLobCreator();
|
||||
if ( value instanceof Clob clob ) {
|
||||
return lobCreator.wrap( clob );
|
||||
}
|
||||
else if ( value instanceof String string ) {
|
||||
return lobCreator.createClob( string );
|
||||
}
|
||||
else if ( value instanceof Reader reader ) {
|
||||
return lobCreator.createClob( extractString( reader ) );
|
||||
}
|
||||
else if ( value instanceof CharacterStream stream ) {
|
||||
return lobCreator.createClob( stream.asReader(), stream.getLength() );
|
||||
}
|
||||
else {
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
}
|
||||
else if ( value instanceof String string ) {
|
||||
return options.getLobCreator().createClob( string );
|
||||
}
|
||||
else if ( value instanceof Reader reader ) {
|
||||
return options.getLobCreator().createClob( DataHelper.extractString( reader ) );
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,7 @@ import java.sql.SQLFeatureNotSupportedException;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -246,7 +246,7 @@ public final class DataHelper {
|
|||
* @return The extracted bytes as a stream
|
||||
*/
|
||||
public static InputStream subStream(InputStream inputStream, long start, int length) {
|
||||
return new BinaryStreamImpl( extractBytes( inputStream, start, length ) );
|
||||
return new ArrayBackedBinaryStream( extractBytes( inputStream, start, length ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public class DoublePrimitiveArrayJavaType extends AbstractArrayJavaType<double[]
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public class FloatPrimitiveArrayJavaType extends AbstractArrayJavaType<float[],
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public class IntegerPrimitiveArrayJavaType extends AbstractArrayJavaType<int[],
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public class LongPrimitiveArrayJavaType extends AbstractArrayJavaType<long[], Lo
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -12,13 +12,15 @@ import java.sql.SQLException;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NClobImplementer;
|
||||
import org.hibernate.engine.jdbc.NClobProxy;
|
||||
import org.hibernate.engine.jdbc.WrappedNClob;
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
import static org.hibernate.type.descriptor.java.DataHelper.extractString;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link NClob} handling.
|
||||
* <p>
|
||||
|
@ -61,7 +63,7 @@ public class NClobJavaType extends AbstractClassJavaType<NClob> {
|
|||
}
|
||||
|
||||
public String toString(NClob value) {
|
||||
return DataHelper.extractString( value );
|
||||
return extractString( value );
|
||||
}
|
||||
|
||||
public NClob fromString(CharSequence string) {
|
||||
|
@ -91,19 +93,43 @@ public class NClobJavaType extends AbstractClassJavaType<NClob> {
|
|||
}
|
||||
|
||||
try {
|
||||
if ( CharacterStream.class.isAssignableFrom( type ) ) {
|
||||
if ( NClob.class.isAssignableFrom( type ) ) {
|
||||
NClob clob = value;
|
||||
if ( clob instanceof WrappedNClob wrappedNClob ) {
|
||||
clob = wrappedNClob.getWrappedNClob();
|
||||
}
|
||||
return (X) options.getLobCreator().createNClob( clob );
|
||||
}
|
||||
else if ( String.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof NClobImplementer clobImplementer) {
|
||||
// if the incoming NClob is a wrapper, just pass along its BinaryStream
|
||||
// if the incoming Clob is a wrapper, just get the underlying String.
|
||||
return (X) clobImplementer.getUnderlyingStream().asString();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to extract the String.
|
||||
return (X) extractString( value.getCharacterStream() );
|
||||
}
|
||||
}
|
||||
else if ( Reader.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof NClobImplementer clobImplementer) {
|
||||
// if the incoming NClob is a wrapper, just pass along its CharacterStream
|
||||
return (X) clobImplementer.getUnderlyingStream().asReader();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a Reader...
|
||||
return (X) value.getCharacterStream();
|
||||
}
|
||||
}
|
||||
else if ( CharacterStream.class.isAssignableFrom( type ) ) {
|
||||
if (value instanceof NClobImplementer clobImplementer) {
|
||||
// if the incoming NClob is a wrapper, just pass along its CharacterStream
|
||||
return (X) clobImplementer.getUnderlyingStream();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a BinaryStream...
|
||||
return (X) new CharacterStreamImpl( DataHelper.extractString( value.getCharacterStream() ) );
|
||||
// otherwise we need to build a CharacterStream...
|
||||
return (X) value.getCharacterStream();
|
||||
}
|
||||
}
|
||||
else if ( NClob.class.isAssignableFrom( type ) ) {
|
||||
return (X) getOrCreateNClob( value, options );
|
||||
}
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new HibernateException( "Unable to access nclob stream", e );
|
||||
|
@ -112,38 +138,27 @@ public class NClobJavaType extends AbstractClassJavaType<NClob> {
|
|||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
private NClob getOrCreateNClob(NClob value, WrapperOptions options) throws SQLException {
|
||||
if ( value instanceof WrappedNClob wrappedNClob ) {
|
||||
value = wrappedNClob.getWrappedNClob();
|
||||
}
|
||||
if ( options.getDialect().useConnectionToCreateLob() ) {
|
||||
if ( value.length() == 0 ) {
|
||||
// empty NClob
|
||||
return options.getLobCreator().createNClob( "" );
|
||||
}
|
||||
else {
|
||||
return options.getLobCreator().createNClob( value.getSubString( 1, (int) value.length() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public <X> NClob wrap(X value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Support multiple return types from
|
||||
// org.hibernate.type.descriptor.sql.ClobTypeDescriptor
|
||||
if ( value instanceof NClob clob ) {
|
||||
return options.getLobCreator().wrap( clob );
|
||||
else {
|
||||
final LobCreator lobCreator = options.getLobCreator();
|
||||
if ( value instanceof NClob clob ) {
|
||||
return lobCreator.wrap( clob );
|
||||
}
|
||||
else if ( value instanceof String string ) {
|
||||
return lobCreator.createNClob( string );
|
||||
}
|
||||
else if ( value instanceof Reader reader ) {
|
||||
return lobCreator.createNClob( extractString( reader ) );
|
||||
}
|
||||
else if ( value instanceof CharacterStream stream ) {
|
||||
return lobCreator.createNClob( stream.asReader(), stream.getLength() );
|
||||
}
|
||||
else {
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
}
|
||||
else if ( value instanceof Reader reader ) {
|
||||
return options.getLobCreator().createNClob( DataHelper.extractString( reader ) );
|
||||
}
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Arrays;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.compare.RowVersionComparator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
|
@ -107,7 +107,7 @@ public class PrimitiveByteArrayJavaType extends AbstractClassJavaType<byte[]>
|
|||
return (X) new ByteArrayInputStream( value );
|
||||
}
|
||||
if ( BinaryStream.class.isAssignableFrom( type ) ) {
|
||||
return (X) new BinaryStreamImpl( value );
|
||||
return (X) new ArrayBackedBinaryStream( value );
|
||||
}
|
||||
if ( Blob.class.isAssignableFrom( type ) ) {
|
||||
return (X) options.getLobCreator().createBlob( value );
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.Arrays;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -107,7 +107,7 @@ public class SerializableJavaType<T extends Serializable> extends AbstractClassJ
|
|||
return (X) new ByteArrayInputStream( toBytes( value ) );
|
||||
}
|
||||
else if ( BinaryStream.class.isAssignableFrom( type ) ) {
|
||||
return (X) new BinaryStreamImpl( toBytes( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( toBytes( value ) );
|
||||
}
|
||||
else if ( Blob.class.isAssignableFrom( type ) ) {
|
||||
return (X) options.getLobCreator().createBlob( toBytes( value ) );
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public class ShortPrimitiveArrayJavaType extends AbstractArrayJavaType<short[],
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( value ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( value ) );
|
||||
}
|
||||
else if ( type.isArray() ) {
|
||||
final Class<?> preferredJavaTypeClass = type.getComponentType();
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.hibernate.SharedSessionContract;
|
|||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.ArrayBackedBinaryStream;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
|
@ -341,7 +341,7 @@ public class BasicCollectionJavaType<C extends Collection<E>, E> extends Abstrac
|
|||
else if ( type == BinaryStream.class ) {
|
||||
// BinaryStream can only be requested if the value should be serialized
|
||||
//noinspection unchecked
|
||||
return (X) new BinaryStreamImpl( SerializationHelper.serialize( asArrayList( value ) ) );
|
||||
return (X) new ArrayBackedBinaryStream( SerializationHelper.serialize( asArrayList( value ) ) );
|
||||
}
|
||||
else if ( type == Object[].class ) {
|
||||
//noinspection unchecked
|
||||
|
|
|
@ -197,6 +197,7 @@ public abstract class BlobJdbcType implements JdbcType {
|
|||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
// the use of BinaryStream here instead of InputStream seems to be only necessary on Oracle
|
||||
final BinaryStream binaryStream = javaType.unwrap( value, BinaryStream.class, options );
|
||||
st.setBinaryStream( index, binaryStream.getInputStream(), binaryStream.getLength() );
|
||||
}
|
||||
|
@ -204,6 +205,7 @@ public abstract class BlobJdbcType implements JdbcType {
|
|||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
// the use of BinaryStream here instead of InputStream seems to be only necessary on Oracle
|
||||
final BinaryStream binaryStream = javaType.unwrap( value, BinaryStream.class, options );
|
||||
st.setBinaryStream( name, binaryStream.getInputStream(), binaryStream.getLength() );
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.hibernate.type.descriptor.jdbc;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -45,7 +46,12 @@ public abstract class NClobJdbcType implements JdbcType {
|
|||
@Override
|
||||
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
|
||||
if ( options.getDialect().supportsNationalizedMethods() ) {
|
||||
return javaType.wrap( rs.getNClob( paramIndex ), options );
|
||||
try {
|
||||
return javaType.wrap( rs.getNClob( paramIndex ), options );
|
||||
}
|
||||
catch (AbstractMethodError e) {
|
||||
return javaType.wrap( rs.getClob( paramIndex ), options );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return javaType.wrap( rs.getClob( paramIndex ), options );
|
||||
|
@ -115,15 +121,15 @@ public abstract class NClobJdbcType implements JdbcType {
|
|||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
getDescriptor( value, options ).getNClobBinder( javaType ).doBind( st, value, index, options );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
getDescriptor( value, options ).getNClobBinder( javaType ).doBind( st, value, name, options );
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
public static final NClobJdbcType STRING_BINDING = new NClobJdbcType() {
|
||||
|
@ -219,7 +225,12 @@ public abstract class NClobJdbcType implements JdbcType {
|
|||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
if ( options.getDialect().supportsNationalizedMethods() ) {
|
||||
st.setNClob( index, javaType.unwrap( value, NClob.class, options ) );
|
||||
try {
|
||||
st.setNClob( index, javaType.unwrap( value, NClob.class, options ) );
|
||||
}
|
||||
catch (AbstractMethodError e) {
|
||||
st.setClob( index, javaType.unwrap( value, Clob.class, options ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
st.setClob( index, javaType.unwrap( value, NClob.class, options ) );
|
||||
|
|
|
@ -63,7 +63,7 @@ public class LobCreatorTest {
|
|||
connection
|
||||
);
|
||||
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(), supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
|
@ -85,7 +85,7 @@ public class LobCreatorTest {
|
|||
connection
|
||||
);
|
||||
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(), supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
|
@ -106,7 +106,7 @@ public class LobCreatorTest {
|
|||
connection
|
||||
);
|
||||
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(), supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
|
@ -128,7 +128,7 @@ public class LobCreatorTest {
|
|||
props,
|
||||
connection
|
||||
);
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(), supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
|
@ -148,7 +148,7 @@ public class LobCreatorTest {
|
|||
Collections.emptyMap(),
|
||||
connection
|
||||
);
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( dialect.useConnectionToCreateLob(), supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
|
|
|
@ -9,8 +9,10 @@ import jakarta.persistence.Id;
|
|||
import jakarta.persistence.Lob;
|
||||
|
||||
import org.hibernate.annotations.Nationalized;
|
||||
import org.hibernate.dialect.SybaseASEDialect;
|
||||
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
@ -19,6 +21,7 @@ import static org.junit.Assert.assertEquals;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@SkipForDialect(dialectClass = SybaseASEDialect.class)
|
||||
public class NClobStringTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
|
@ -34,7 +37,7 @@ public class NClobStringTest extends BaseEntityManagerFunctionalTestCase {
|
|||
final Product product = new Product();
|
||||
product.setId(1);
|
||||
product.setName("Mobile phone");
|
||||
product.setWarranty("My product warranty");
|
||||
product.setWarranty("My product®™ warranty 😍");
|
||||
|
||||
entityManager.persist(product);
|
||||
return product.getId();
|
||||
|
@ -42,7 +45,7 @@ public class NClobStringTest extends BaseEntityManagerFunctionalTestCase {
|
|||
doInJPA(this::entityManagerFactory, entityManager -> {
|
||||
Product product = entityManager.find(Product.class, productId);
|
||||
|
||||
assertEquals("My product warranty", product.getWarranty());
|
||||
assertEquals("My product®™ warranty 😍", product.getWarranty());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,22 +4,20 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.mapping.basic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.sql.NClob;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
|
||||
import org.hibernate.annotations.Nationalized;
|
||||
import org.hibernate.dialect.SybaseASEDialect;
|
||||
import org.hibernate.engine.jdbc.NClobProxy;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -35,13 +33,14 @@ import static org.junit.Assert.fail;
|
|||
"because we explicitly map this attribute to the `NClob` java type the database really" +
|
||||
" has to support those types"
|
||||
)
|
||||
@SkipForDialect(dialectClass = SybaseASEDialect.class)
|
||||
public class NClobTest {
|
||||
@Test
|
||||
public void test(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
(entityManager) -> {
|
||||
//tag::basic-nclob-persist-example[]
|
||||
String warranty = "My product warranty";
|
||||
String warranty = "My product®™ warranty 😍";
|
||||
|
||||
final Product product = new Product();
|
||||
product.setId(1);
|
||||
|
@ -60,33 +59,17 @@ public class NClobTest {
|
|||
//tag::basic-nclob-find-example[]
|
||||
Product product = entityManager.find(Product.class, 1);
|
||||
|
||||
try (Reader reader = product.getWarranty().getCharacterStream()) {
|
||||
assertEquals("My product warranty", toString(reader));
|
||||
}
|
||||
NClob warranty = product.getWarranty();
|
||||
assertEquals("My product®™ warranty 😍", warranty.getSubString( 1, (int) warranty.length() ) );
|
||||
//end::basic-nclob-find-example[]
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
private String toString(Reader reader) throws IOException {
|
||||
BufferedReader bufferedReader = new BufferedReader(reader);
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
int result = bufferedReader.read();
|
||||
|
||||
while (result != -1) {
|
||||
byteArrayOutputStream.write((byte) result);
|
||||
result = bufferedReader.read();
|
||||
}
|
||||
|
||||
return byteArrayOutputStream.toString();
|
||||
}
|
||||
|
||||
|
||||
//tag::basic-nclob-example[]
|
||||
@Entity(name = "Product")
|
||||
public static class Product {
|
||||
|
|
Loading…
Reference in New Issue