HHH-16321 - Hibernate maps NCLOB to ntext on Sybase
This commit is contained in:
parent
48c59392f6
commit
06381d2dd2
|
@ -47,6 +47,7 @@ import jakarta.persistence.TemporalType;
|
|||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.DATE;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
|
@ -96,20 +97,28 @@ public class SybaseASEDialect extends SybaseDialect {
|
|||
@Override
|
||||
protected String columnType(int sqlTypeCode) {
|
||||
switch ( sqlTypeCode ) {
|
||||
case BOOLEAN:
|
||||
case BOOLEAN: {
|
||||
// On Sybase ASE, the 'bit' type cannot be null,
|
||||
// and cannot have indexes (while we don't use
|
||||
// tinyint to store signed bytes, we can use it
|
||||
// to store boolean values)
|
||||
return "tinyint";
|
||||
case DATE:
|
||||
}
|
||||
case DATE: {
|
||||
return "date";
|
||||
case TIME:
|
||||
}
|
||||
case TIME: {
|
||||
return "time";
|
||||
default:
|
||||
}
|
||||
case NCLOB: {
|
||||
// Sybase uses `unitext` instead of the T-SQL `ntext` type name
|
||||
return "unitext";
|
||||
}
|
||||
default: {
|
||||
return super.columnType( sqlTypeCode );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
|
|
|
@ -179,8 +179,12 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
jdbcTypeRegistry.addDescriptor( Types.NVARCHAR, ClobJdbcType.CLOB_BINDING );
|
||||
}
|
||||
else {
|
||||
// Some Sybase drivers cannot support getClob. See HHH-7889
|
||||
// jConnect driver only conditionally supports getClob/getNClob depending on a server setting. See
|
||||
// - https://help.sap.com/doc/e3cb6844decf441e85e4670e1cf48c9b/16.0.3.6/en-US/SAP_jConnect_Programmers_Reference_en.pdf
|
||||
// - https://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc20155.1570/html/OS_SDK_nf/CIHJFDDH.htm
|
||||
// - HHH-7889
|
||||
jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcType.STREAM_BINDING_EXTRACTING );
|
||||
jdbcTypeRegistry.addDescriptor( Types.NCLOB, ClobJdbcType.STREAM_BINDING_EXTRACTING );
|
||||
}
|
||||
|
||||
jdbcTypeRegistry.addDescriptor( Types.BLOB, BlobJdbcType.PRIMITIVE_ARRAY_BINDING );
|
||||
|
|
|
@ -17,6 +17,7 @@ public interface LobCreationContext {
|
|||
/**
|
||||
* The callback contract for making use of the JDBC {@link Connection}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface Callback<T> {
|
||||
/**
|
||||
* Perform whatever actions are necessary using the provided JDBC {@link Connection}.
|
||||
|
@ -28,6 +29,10 @@ public interface LobCreationContext {
|
|||
* @throws SQLException Indicates trouble accessing the JDBC driver to create the LOB
|
||||
*/
|
||||
T executeOnConnection(Connection connection) throws SQLException;
|
||||
|
||||
default T from(Connection connection) throws SQLException {
|
||||
return executeOnConnection( connection );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,4 +45,8 @@ public interface LobCreationContext {
|
|||
* @return The LOB created by the callback.
|
||||
*/
|
||||
<T> T execute(Callback<T> callback);
|
||||
|
||||
default <T> T fromContext(Callback<T> callback) {
|
||||
return execute( callback );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
@ -15,23 +15,35 @@ import java.sql.NClob;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.jdbc.AbstractLobCreator;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NClobProxy;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
|
||||
/**
|
||||
* {@link LobCreator} implementation using contextual creation against the JDBC {@link Connection} class's LOB creation
|
||||
* methods.
|
||||
* LobCreator which can use {@link Connection#createBlob} and {@link Connection#createClob},
|
||||
* but {@link java.sql.NClob} references are created locally.
|
||||
*
|
||||
* @see NClobProxy
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class ContextualLobCreator extends AbstractLobCreator implements LobCreator {
|
||||
private final LobCreationContext lobCreationContext;
|
||||
public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator {
|
||||
|
||||
/**
|
||||
* Constructs a ContextualLobCreator
|
||||
*
|
||||
* @param lobCreationContext The context for performing LOB creation
|
||||
* Callback for performing contextual BLOB creation
|
||||
*/
|
||||
public ContextualLobCreator(LobCreationContext lobCreationContext) {
|
||||
public static final LobCreationContext.Callback<Blob> CREATE_BLOB_CALLBACK = Connection::createBlob;
|
||||
|
||||
/**
|
||||
* Callback for performing contextual CLOB creation
|
||||
*/
|
||||
public static final LobCreationContext.Callback<Clob> CREATE_CLOB_CALLBACK = Connection::createClob;
|
||||
|
||||
protected final LobCreationContext lobCreationContext;
|
||||
|
||||
public BlobAndClobCreator(LobCreationContext lobCreationContext) {
|
||||
this.lobCreationContext = lobCreationContext;
|
||||
}
|
||||
|
||||
|
@ -41,13 +53,13 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
* @return The created BLOB reference.
|
||||
*/
|
||||
public Blob createBlob() {
|
||||
return lobCreationContext.execute( CREATE_BLOB_CALLBACK );
|
||||
return lobCreationContext.fromContext( CREATE_BLOB_CALLBACK );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob(byte[] bytes) {
|
||||
try {
|
||||
final Blob blob = createBlob();
|
||||
try {
|
||||
blob.setBytes( 1, bytes );
|
||||
return blob;
|
||||
}
|
||||
|
@ -57,10 +69,10 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob(InputStream inputStream, long length) {
|
||||
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).
|
||||
return NonContextualLobCreator.INSTANCE.createBlob( inputStream, length );
|
||||
return NonContextualLobCreator.INSTANCE.createBlob( stream, length );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,7 +81,7 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
* @return The created CLOB reference.
|
||||
*/
|
||||
public Clob createClob() {
|
||||
return lobCreationContext.execute( CREATE_CLOB_CALLBACK );
|
||||
return lobCreationContext.fromContext( CREATE_CLOB_CALLBACK );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,46 +103,13 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
return NonContextualLobCreator.INSTANCE.createClob( reader, length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the basic contextual NCLOB reference.
|
||||
*
|
||||
* @return The created NCLOB reference.
|
||||
*/
|
||||
public NClob createNClob() {
|
||||
return lobCreationContext.execute( CREATE_NCLOB_CALLBACK );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob(String string) {
|
||||
try {
|
||||
final NClob nclob = createNClob();
|
||||
nclob.setString( 1, string );
|
||||
return nclob;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new JDBCException( "Unable to set NCLOB string after creation", e );
|
||||
}
|
||||
return NonContextualLobCreator.INSTANCE.createNClob( string );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob(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).
|
||||
return NonContextualLobCreator.INSTANCE.createNClob( reader, length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for performing contextual BLOB creation
|
||||
*/
|
||||
public static final LobCreationContext.Callback<Blob> CREATE_BLOB_CALLBACK = Connection::createBlob;
|
||||
|
||||
/**
|
||||
* Callback for performing contextual CLOB creation
|
||||
*/
|
||||
public static final LobCreationContext.Callback<Clob> CREATE_CLOB_CALLBACK = Connection::createClob;
|
||||
|
||||
/**
|
||||
* Callback for performing contextual NCLOB creation
|
||||
*/
|
||||
public static final LobCreationContext.Callback<NClob> CREATE_NCLOB_CALLBACK = Connection::createNClob;
|
||||
}
|
118
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/LobCreationHelper.java
vendored
Normal file
118
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/LobCreationHelper.java
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreationLogging.LOB_LOGGER;
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreationLogging.LOB_MESSAGE_LOGGER;
|
||||
|
||||
/**
|
||||
* Utilities for LOB creation
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LobCreationHelper {
|
||||
public static final EnumSet<LobTypes> NONE = EnumSet.noneOf( LobTypes.class );
|
||||
|
||||
/**
|
||||
* Basically here we are simply checking whether we can call the {@link Connection} methods for
|
||||
* LOB creation added in JDBC 4. We not only check whether the {@link Connection} declares these methods,
|
||||
* but also whether the actual {@link Connection} instance implements them (i.e. can be called without simply
|
||||
* throwing an exception).
|
||||
*
|
||||
* @param dialect The {@link Dialect} in use
|
||||
* @param configValues The map of settings
|
||||
* @param jdbcConnection The connection which can be used in level-of-support testing.
|
||||
*/
|
||||
public static EnumSet<LobTypes> getSupportedContextualLobTypes(Dialect dialect, Map<String,Object> configValues, Connection jdbcConnection) {
|
||||
if ( ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, configValues ) ) {
|
||||
LOB_MESSAGE_LOGGER.disablingContextualLOBCreation( Environment.NON_CONTEXTUAL_LOB_CREATION );
|
||||
return NONE;
|
||||
}
|
||||
|
||||
if ( jdbcConnection == null ) {
|
||||
LOB_MESSAGE_LOGGER.disablingContextualLOBCreationSinceConnectionNull();
|
||||
return NONE;
|
||||
}
|
||||
|
||||
try {
|
||||
final DatabaseMetaData meta = jdbcConnection.getMetaData();
|
||||
// if the jdbc driver version is less than 4, it shouldn't have createClob
|
||||
if ( meta.getJDBCMajorVersion() < 4 ) {
|
||||
LOB_MESSAGE_LOGGER.nonContextualLobCreationJdbcVersion( meta.getJDBCMajorVersion() );
|
||||
return NONE;
|
||||
}
|
||||
|
||||
if ( !dialect.supportsJdbcConnectionLobCreation( meta ) ) {
|
||||
LOB_MESSAGE_LOGGER.nonContextualLobCreationDialect();
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
// ignore exception and continue
|
||||
}
|
||||
|
||||
// NOTE : for the time being we assume that the ability to call
|
||||
// `createClob` implies the ability to call `#createBlob`
|
||||
if ( canCreateClob( jdbcConnection ) ) {
|
||||
if ( canCreateNClob( jdbcConnection ) ) {
|
||||
return EnumSet.of( LobTypes.BLOB, LobTypes.CLOB, LobTypes.NCLOB );
|
||||
}
|
||||
else {
|
||||
return EnumSet.of( LobTypes.BLOB, LobTypes.CLOB );
|
||||
}
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private static boolean canCreateClob(Connection jdbcConnection) {
|
||||
try {
|
||||
// we just want to see if the driver can create one. we can immediately free it.
|
||||
final Clob clob = jdbcConnection.createClob();
|
||||
try {
|
||||
clob.free();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOB_LOGGER.tracef( "Unable to free CLOB created to test createClob() implementation : %s", e );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
LOB_MESSAGE_LOGGER.contextualClobCreationFailed( e );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canCreateNClob(Connection jdbcConnection) {
|
||||
try {
|
||||
// we just want to see if the driver can create one. we can immediately free it.
|
||||
final Clob clob = jdbcConnection.createNClob();
|
||||
try {
|
||||
clob.free();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOB_LOGGER.tracef( "Unable to free NCLOB created to test createNClob() implementation : %s", e );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
LOB_MESSAGE_LOGGER.contextualNClobCreationFailed( e );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
63
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/LobCreationLogging.java
vendored
Normal file
63
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/LobCreationLogging.java
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import org.hibernate.boot.BootLogging;
|
||||
import org.hibernate.engine.jdbc.JdbcLogging;
|
||||
import org.hibernate.internal.log.SubSystemLogging;
|
||||
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.LogMessage;
|
||||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
import org.jboss.logging.annotations.ValidIdRange;
|
||||
|
||||
import static org.jboss.logging.Logger.Level.DEBUG;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SubSystemLogging(
|
||||
name = BootLogging.NAME,
|
||||
description = "Logging related to "
|
||||
)
|
||||
@MessageLogger( projectCode = "HHH" )
|
||||
@ValidIdRange( min = 10010001, max = 10010050 )
|
||||
public interface LobCreationLogging extends BasicLogger {
|
||||
String NAME = JdbcLogging.NAME + ".lob";
|
||||
|
||||
Logger LOB_LOGGER = Logger.getLogger( NAME );
|
||||
LobCreationLogging LOB_MESSAGE_LOGGER = Logger.getMessageLogger( LobCreationLogging.class, NAME );
|
||||
|
||||
boolean LOB_TRACE_ENABLED = LOB_LOGGER.isTraceEnabled();
|
||||
boolean LOB_DEBUG_ENABLED = LOB_LOGGER.isDebugEnabled();
|
||||
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as %s is true", id = 10010001)
|
||||
void disablingContextualLOBCreation(String settingName);
|
||||
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as connection was null", id = 10010002)
|
||||
void disablingContextualLOBCreationSinceConnectionNull();
|
||||
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as JDBC driver reported JDBC version [%s] less than 4", id = 10010003)
|
||||
void nonContextualLobCreationJdbcVersion(int jdbcMajorVersion);
|
||||
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as Dialect reported it is not supported", id = 10010004)
|
||||
void nonContextualLobCreationDialect();
|
||||
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as createClob() method threw error : %s", id = 10010005)
|
||||
void contextualClobCreationFailed(Throwable t);
|
||||
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual NCLOB creation as createNClob() method threw error : %s", id = 10010006)
|
||||
void contextualNClobCreationFailed(Throwable t);
|
||||
}
|
|
@ -6,24 +6,20 @@
|
|||
*/
|
||||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.ContextualLobCreator;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
import org.hibernate.engine.jdbc.env.spi.LobCreatorBuilder;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreationHelper.NONE;
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreationHelper.getSupportedContextualLobTypes;
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreationLogging.LOB_LOGGER;
|
||||
import static org.hibernate.engine.jdbc.env.internal.LobCreationLogging.LOB_MESSAGE_LOGGER;
|
||||
|
||||
/**
|
||||
* Builds {@link LobCreator} instances based on the capabilities of the environment.
|
||||
|
@ -31,15 +27,10 @@ import org.jboss.logging.Logger;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
LobCreatorBuilderImpl.class.getName()
|
||||
);
|
||||
private final EnumSet<LobTypes> supportedContextualLobTypes;
|
||||
|
||||
private final boolean useContextualLobCreation;
|
||||
|
||||
private LobCreatorBuilderImpl(boolean useContextualLobCreation) {
|
||||
this.useContextualLobCreation = useContextualLobCreation;
|
||||
public LobCreatorBuilderImpl(EnumSet<LobTypes> supportedContextualLobTypes) {
|
||||
this.supportedContextualLobTypes = supportedContextualLobTypes;
|
||||
}
|
||||
|
||||
// factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -53,8 +44,17 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
|||
* @param jdbcConnection A JDBC {@link Connection} which can be used to gauge the drivers level of support,
|
||||
* specifically for creating LOB references.
|
||||
*/
|
||||
public static LobCreatorBuilderImpl makeLobCreatorBuilder(Dialect dialect, Map<String,Object> configValues, Connection jdbcConnection) {
|
||||
return new LobCreatorBuilderImpl( useContextualLobCreation( dialect, configValues, jdbcConnection ) );
|
||||
public static LobCreatorBuilderImpl makeLobCreatorBuilder(
|
||||
Dialect dialect,
|
||||
Map<String,Object> configValues,
|
||||
Connection jdbcConnection) {
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
configValues,
|
||||
jdbcConnection
|
||||
);
|
||||
|
||||
return new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,80 +63,8 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
|||
* @return Appropriate LobCreatorBuilder
|
||||
*/
|
||||
public static LobCreatorBuilderImpl makeLobCreatorBuilder() {
|
||||
LOG.disablingContextualLOBCreationSinceConnectionNull();
|
||||
return new LobCreatorBuilderImpl( false );
|
||||
}
|
||||
|
||||
private static final Class<?>[] NO_ARG_SIG = ArrayHelper.EMPTY_CLASS_ARRAY;
|
||||
private static final Object[] NO_ARGS = ArrayHelper.EMPTY_OBJECT_ARRAY;
|
||||
|
||||
/**
|
||||
* Basically here we are simply checking whether we can call the {@link Connection} methods for
|
||||
* LOB creation added in JDBC 4. We not only check whether the {@link Connection} declares these methods,
|
||||
* but also whether the actual {@link Connection} instance implements them (i.e. can be called without simply
|
||||
* throwing an exception).
|
||||
*
|
||||
* @param dialect The {@link Dialect} in use
|
||||
* @param configValues The map of settings
|
||||
* @param jdbcConnection The connection which can be used in level-of-support testing.
|
||||
*
|
||||
* @return True if the connection can be used to create LOBs; false otherwise.
|
||||
*/
|
||||
private static boolean useContextualLobCreation(Dialect dialect, Map<String,Object> configValues, Connection jdbcConnection) {
|
||||
final boolean isNonContextualLobCreationRequired =
|
||||
ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, configValues );
|
||||
if ( isNonContextualLobCreationRequired ) {
|
||||
LOG.disablingContextualLOBCreation( Environment.NON_CONTEXTUAL_LOB_CREATION );
|
||||
return false;
|
||||
}
|
||||
if ( jdbcConnection == null ) {
|
||||
LOG.disablingContextualLOBCreationSinceConnectionNull();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
final DatabaseMetaData meta = jdbcConnection.getMetaData();
|
||||
// if the jdbc driver version is less than 4, it shouldn't have createClob
|
||||
if ( meta.getJDBCMajorVersion() < 4 ) {
|
||||
LOG.disablingContextualLOBCreationSinceOldJdbcVersion( meta.getJDBCMajorVersion() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !dialect.supportsJdbcConnectionLobCreation( meta ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch ( SQLException ignore ) {
|
||||
// ignore exception and continue
|
||||
}
|
||||
|
||||
final Class<?> connectionClass = Connection.class;
|
||||
final Method createClobMethod = connectionClass.getMethod( "createClob", NO_ARG_SIG );
|
||||
if ( createClobMethod.getDeclaringClass().equals( Connection.class ) ) {
|
||||
// If we get here we are running in a jdk 1.6 (jdbc 4) environment:
|
||||
// Further check to make sure the driver actually implements the LOB creation methods.
|
||||
// We check against createClob() as indicative of all; should we check against all 3 explicitly?
|
||||
try {
|
||||
final Object clob = createClobMethod.invoke( jdbcConnection, NO_ARGS );
|
||||
try {
|
||||
final Method freeMethod = clob.getClass().getMethod( "free", NO_ARG_SIG );
|
||||
freeMethod.invoke( clob, NO_ARGS );
|
||||
}
|
||||
catch ( Throwable e ) {
|
||||
LOG.tracef( "Unable to free CLOB created to test createClob() implementation : %s", e );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
LOG.disablingContextualLOBCreationSinceCreateClobFailed( t );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( NoSuchMethodException ignore ) {
|
||||
}
|
||||
|
||||
return false;
|
||||
LOB_MESSAGE_LOGGER.disablingContextualLOBCreationSinceConnectionNull();
|
||||
return new LobCreatorBuilderImpl( NONE );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,8 +75,20 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
|
|||
* @return The LobCreator
|
||||
*/
|
||||
public LobCreator buildLobCreator(LobCreationContext lobCreationContext) {
|
||||
return useContextualLobCreation
|
||||
? new ContextualLobCreator( lobCreationContext )
|
||||
: NonContextualLobCreator.INSTANCE;
|
||||
if ( supportedContextualLobTypes.isEmpty() ) {
|
||||
return NonContextualLobCreator.INSTANCE;
|
||||
}
|
||||
|
||||
if ( supportedContextualLobTypes.contains( LobTypes.BLOB )
|
||||
&& supportedContextualLobTypes.contains( LobTypes.CLOB ) ){
|
||||
if ( !supportedContextualLobTypes.contains( LobTypes.NCLOB ) ) {
|
||||
return new BlobAndClobCreator( lobCreationContext );
|
||||
}
|
||||
|
||||
return new StandardLobCreator( lobCreationContext );
|
||||
}
|
||||
|
||||
LOB_LOGGER.debug( "Unexpected condition resolving type of LobCreator to use. Falling back to NonContextualLobCreator" );
|
||||
return NonContextualLobCreator.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
|
40
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/LobTypes.java
vendored
Normal file
40
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/LobTypes.java
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.NClob;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
/**
|
||||
* Enumeration of the JDBC LOB locator types
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public enum LobTypes {
|
||||
BLOB( SqlTypes.BLOB, Blob.class ),
|
||||
CLOB( SqlTypes.CLOB, Clob.class ),
|
||||
NCLOB( SqlTypes.NCLOB, NClob.class );
|
||||
|
||||
private final int jdbcTypeCode;
|
||||
private final Class<?> jdbcTypeClass;
|
||||
|
||||
LobTypes(int jdbcTypeCode, Class<?> jdbcTypeClass) {
|
||||
this.jdbcTypeCode = jdbcTypeCode;
|
||||
this.jdbcTypeClass = jdbcTypeClass;
|
||||
}
|
||||
|
||||
public int getJdbcTypeCode() {
|
||||
return jdbcTypeCode;
|
||||
}
|
||||
|
||||
public Class<?> getJdbcTypeClass() {
|
||||
return jdbcTypeClass;
|
||||
}
|
||||
}
|
67
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/StandardLobCreator.java
vendored
Normal file
67
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/StandardLobCreator.java
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.NClob;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
|
||||
/**
|
||||
* {@linkplain LobCreator} implementation using {@linkplain Connection#createBlob},
|
||||
* {@linkplain Connection#createClob} and {@linkplain Connection#createNClob} to
|
||||
* create the LOB references.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class StandardLobCreator extends BlobAndClobCreator {
|
||||
/**
|
||||
* Callback for performing contextual NCLOB creation
|
||||
*/
|
||||
public static final LobCreationContext.Callback<NClob> CREATE_NCLOB_CALLBACK = Connection::createNClob;
|
||||
|
||||
public StandardLobCreator(LobCreationContext lobCreationContext) {
|
||||
super( lobCreationContext );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the basic contextual NCLOB reference.
|
||||
*
|
||||
* @return The created NCLOB reference.
|
||||
*/
|
||||
public NClob createNClob() {
|
||||
return lobCreationContext.fromContext( CREATE_NCLOB_CALLBACK );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob(String string) {
|
||||
try {
|
||||
final NClob nclob = createNClob();
|
||||
nclob.setString( 1, string );
|
||||
return nclob;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new JDBCException( "Unable to set NCLOB string after creation", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob(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).
|
||||
return NonContextualLobCreator.INSTANCE.createNClob( reader, length );
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.jdbc.ContextualLobCreator;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.PropertiesHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Builds {@link LobCreator} instances based on the capabilities of the environment.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LobCreatorBuilder {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
LobCreatorBuilder.class.getName()
|
||||
);
|
||||
|
||||
private final boolean useContextualLobCreation;
|
||||
|
||||
/**
|
||||
* The public factory method for obtaining the appropriate according to given JDBC {@link Connection}.
|
||||
*
|
||||
* @param configValues The map of settings
|
||||
* @param jdbcConnection A JDBC {@link Connection} which can be used to gauge the drivers level of support,
|
||||
* specifically for creating LOB references.
|
||||
*/
|
||||
public LobCreatorBuilder(Map<String,Object> configValues, Connection jdbcConnection) {
|
||||
this.useContextualLobCreation = useContextualLobCreation( configValues, jdbcConnection );
|
||||
}
|
||||
|
||||
public LobCreatorBuilder(Properties configValues, Connection jdbcConnection) {
|
||||
this( PropertiesHelper.map(configValues), jdbcConnection );
|
||||
}
|
||||
|
||||
private static final Class<?>[] NO_ARG_SIG = ArrayHelper.EMPTY_CLASS_ARRAY;
|
||||
private static final Object[] NO_ARGS = ArrayHelper.EMPTY_OBJECT_ARRAY;
|
||||
|
||||
/**
|
||||
* Basically here we are simply checking whether we can call the {@link Connection} methods for
|
||||
* LOB creation added in JDBC 4. We not only check whether the {@link Connection} declares these methods,
|
||||
* but also whether the actual {@link Connection} instance implements them (i.e. can be called without simply
|
||||
* throwing an exception).
|
||||
*
|
||||
* @param jdbcConnection The connection which can be used in level-of-support testing.
|
||||
*
|
||||
* @return True if the connection can be used to create LOBs; false otherwise.
|
||||
*/
|
||||
private static boolean useContextualLobCreation(Map<String,Object> configValues, Connection jdbcConnection) {
|
||||
final boolean isNonContextualLobCreationRequired =
|
||||
ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, configValues );
|
||||
if ( isNonContextualLobCreationRequired ) {
|
||||
LOG.disablingContextualLOBCreation( Environment.NON_CONTEXTUAL_LOB_CREATION );
|
||||
return false;
|
||||
}
|
||||
if ( jdbcConnection == null ) {
|
||||
LOG.disablingContextualLOBCreationSinceConnectionNull();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
final DatabaseMetaData meta = jdbcConnection.getMetaData();
|
||||
// if the jdbc driver version is less than 4, it shouldn't have createClob
|
||||
if ( meta.getJDBCMajorVersion() < 4 ) {
|
||||
LOG.disablingContextualLOBCreationSinceOldJdbcVersion( meta.getJDBCMajorVersion() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch ( SQLException ignore ) {
|
||||
// ignore exception and continue
|
||||
}
|
||||
|
||||
final Class<Connection> connectionClass = Connection.class;
|
||||
final Method createClobMethod = connectionClass.getMethod( "createClob", NO_ARG_SIG );
|
||||
if ( createClobMethod.getDeclaringClass().equals( Connection.class ) ) {
|
||||
// If we get here we are running in a jdk 1.6 (jdbc 4) environment:
|
||||
// Further check to make sure the driver actually implements the LOB creation methods.
|
||||
// We check against createClob() as indicative of all; should we check against all 3 explicitly?
|
||||
try {
|
||||
final Object clob = createClobMethod.invoke( jdbcConnection, NO_ARGS );
|
||||
try {
|
||||
final Method freeMethod = clob.getClass().getMethod( "free", NO_ARG_SIG );
|
||||
freeMethod.invoke( clob, NO_ARGS );
|
||||
}
|
||||
catch ( Throwable e ) {
|
||||
LOG.tracef( "Unable to free CLOB created to test createClob() implementation : %s", e );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
LOG.disablingContextualLOBCreationSinceCreateClobFailed( t );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( NoSuchMethodException ignore ) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a LobCreator using the given context
|
||||
*
|
||||
* @param lobCreationContext The LOB creation context
|
||||
*
|
||||
* @return The LobCreator
|
||||
*/
|
||||
public LobCreator buildLobCreator(LobCreationContext lobCreationContext) {
|
||||
return useContextualLobCreation
|
||||
? new ContextualLobCreator( lobCreationContext )
|
||||
: NonContextualLobCreator.INSTANCE;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.hibernate.cache.CacheException;
|
|||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
|
||||
import org.hibernate.engine.jdbc.env.internal.LobCreationLogging;
|
||||
import org.hibernate.engine.jndi.JndiException;
|
||||
import org.hibernate.engine.jndi.JndiNameException;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
|
@ -1425,21 +1426,40 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
@Message(value = "Closing un-released batch", id = 420)
|
||||
void closingUnreleasedBatch();
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link LobCreationLogging#disablingContextualLOBCreation} instead
|
||||
*/
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as %s is true", id = 421)
|
||||
@Deprecated
|
||||
void disablingContextualLOBCreation(String nonContextualLobCreation);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link LobCreationLogging#disablingContextualLOBCreationSinceConnectionNull} instead
|
||||
*/
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as connection was null", id = 422)
|
||||
@Deprecated
|
||||
void disablingContextualLOBCreationSinceConnectionNull();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link LobCreationLogging#nonContextualLobCreationJdbcVersion} instead
|
||||
*/
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as JDBC driver reported JDBC version [%s] less than 4",
|
||||
id = 423)
|
||||
@Message(value = "Disabling contextual LOB creation as JDBC driver reported JDBC version [%s] less than 4", id = 423)
|
||||
@Deprecated
|
||||
void disablingContextualLOBCreationSinceOldJdbcVersion(int jdbcMajorVersion);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link LobCreationLogging#contextualClobCreationFailed} instead
|
||||
*
|
||||
* @see LobCreationLogging#contextualClobCreationFailed
|
||||
* @see LobCreationLogging#contextualNClobCreationFailed
|
||||
*/
|
||||
@LogMessage(level = DEBUG)
|
||||
@Message(value = "Disabling contextual LOB creation as createClob() method threw error : %s", id = 424)
|
||||
@Deprecated
|
||||
void disablingContextualLOBCreationSinceCreateClobFailed(Throwable t);
|
||||
|
||||
@LogMessage(level = INFO)
|
||||
|
|
|
@ -19,80 +19,142 @@ import java.sql.Connection;
|
|||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.engine.jdbc.BlobImplementer;
|
||||
import org.hibernate.engine.jdbc.ClobImplementer;
|
||||
import org.hibernate.engine.jdbc.ContextualLobCreator;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NClobImplementer;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
import org.hibernate.engine.jdbc.WrappedBlob;
|
||||
import org.hibernate.engine.jdbc.WrappedClob;
|
||||
import org.hibernate.engine.jdbc.internal.LobCreatorBuilder;
|
||||
import org.hibernate.engine.jdbc.env.internal.BlobAndClobCreator;
|
||||
import org.hibernate.engine.jdbc.env.internal.LobCreationHelper;
|
||||
import org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl;
|
||||
import org.hibernate.engine.jdbc.env.internal.LobTypes;
|
||||
import org.hibernate.engine.jdbc.env.internal.StandardLobCreator;
|
||||
|
||||
import static org.junit.Assert.assertSame;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LobCreatorTest extends org.hibernate.testing.junit4.BaseUnitTestCase {
|
||||
public class LobCreatorTest {
|
||||
|
||||
@Test
|
||||
public void testConnectedLobCreator() throws SQLException {
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl( true ) );
|
||||
LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl( LobTypes.BLOB, LobTypes.CLOB, LobTypes.NCLOB ) );
|
||||
final H2Dialect dialect = new H2Dialect();
|
||||
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = LobCreationHelper.getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
Collections.emptyMap(),
|
||||
connection
|
||||
);
|
||||
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
assertThat( lobCreator ).isInstanceOf( StandardLobCreator.class );
|
||||
|
||||
LobCreator lobCreator =
|
||||
new LobCreatorBuilder( new Properties(), connection )
|
||||
.buildLobCreator( lobCreationContext );
|
||||
assertTrue( lobCreator instanceof ContextualLobCreator );
|
||||
testLobCreation( lobCreator );
|
||||
|
||||
connection.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJdbc3LobCreator() throws SQLException {
|
||||
final Connection connection = createConnectionProxy( 3, new JdbcLobBuilderImpl( false) );
|
||||
LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
final Connection connection = createConnectionProxy( 3, new JdbcLobBuilderImpl() );
|
||||
final H2Dialect dialect = new H2Dialect();
|
||||
|
||||
LobCreator lobCreator =
|
||||
new LobCreatorBuilder( new Properties(), connection )
|
||||
.buildLobCreator( lobCreationContext );
|
||||
assertSame( NonContextualLobCreator.INSTANCE, lobCreator );
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = LobCreationHelper.getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
Collections.emptyMap(),
|
||||
connection
|
||||
);
|
||||
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
assertThat( lobCreator ).isSameAs( NonContextualLobCreator.INSTANCE );
|
||||
|
||||
testLobCreation( lobCreator );
|
||||
|
||||
connection.close();
|
||||
}
|
||||
@Test
|
||||
public void testJdbc4UnsupportedLobCreator() throws SQLException {
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl( false ) );
|
||||
LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl() );
|
||||
final H2Dialect dialect = new H2Dialect();
|
||||
|
||||
LobCreator lobCreator =
|
||||
new LobCreatorBuilder( new Properties(), connection )
|
||||
.buildLobCreator( lobCreationContext );
|
||||
assertSame( NonContextualLobCreator.INSTANCE, lobCreator );
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = LobCreationHelper.getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
Collections.emptyMap(),
|
||||
connection
|
||||
);
|
||||
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
assertThat( lobCreator ).isSameAs( NonContextualLobCreator.INSTANCE );
|
||||
|
||||
testLobCreation( lobCreator );
|
||||
|
||||
connection.close();
|
||||
}
|
||||
@Test
|
||||
public void testConfiguredNonContextualLobCreator() throws SQLException {
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl( true ) );
|
||||
LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl( LobTypes.BLOB, LobTypes.CLOB, LobTypes.NCLOB ) );
|
||||
final H2Dialect dialect = new H2Dialect();
|
||||
final Map<String,Object> props = new HashMap<>();
|
||||
props.put( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" );
|
||||
|
||||
Properties props = new Properties();
|
||||
props.setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" );
|
||||
LobCreator lobCreator =
|
||||
new LobCreatorBuilder( props, connection )
|
||||
.buildLobCreator( lobCreationContext );
|
||||
assertSame( NonContextualLobCreator.INSTANCE, lobCreator );
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = LobCreationHelper.getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
props,
|
||||
connection
|
||||
);
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
assertThat( lobCreator ).isSameAs( NonContextualLobCreator.INSTANCE );
|
||||
|
||||
testLobCreation( lobCreator );
|
||||
connection.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlobAndClob() throws SQLException {
|
||||
// no NCLOB
|
||||
final Connection connection = createConnectionProxy( 4, new JdbcLobBuilderImpl( LobTypes.BLOB, LobTypes.CLOB ) );
|
||||
final SybaseDialect dialect = new SybaseDialect();
|
||||
final EnumSet<LobTypes> supportedContextualLobTypes = LobCreationHelper.getSupportedContextualLobTypes(
|
||||
dialect,
|
||||
Collections.emptyMap(),
|
||||
connection
|
||||
);
|
||||
final LobCreatorBuilderImpl creatorBuilder = new LobCreatorBuilderImpl( supportedContextualLobTypes );
|
||||
final LobCreationContext lobCreationContext = new LobCreationContextImpl( connection );
|
||||
|
||||
final LobCreator lobCreator = creatorBuilder.buildLobCreator( lobCreationContext );
|
||||
assertThat( lobCreator ).isInstanceOf( BlobAndClobCreator.class );
|
||||
|
||||
testLobCreation( lobCreator );
|
||||
connection.close();
|
||||
|
@ -124,7 +186,7 @@ public class LobCreatorTest extends org.hibernate.testing.junit4.BaseUnitTestCas
|
|||
assertTrue( nclob instanceof NClobImplementer );
|
||||
}
|
||||
else {
|
||||
assertTrue( nclob instanceof JdbcNClob );
|
||||
assertTrue( nclob instanceof NClob );
|
||||
}
|
||||
// assertTrue( nclob instanceof NClob );
|
||||
nclob = lobCreator.wrap( nclob );
|
||||
|
@ -159,27 +221,34 @@ public class LobCreatorTest extends org.hibernate.testing.junit4.BaseUnitTestCas
|
|||
}
|
||||
|
||||
private static class JdbcLobBuilderImpl implements JdbcLobBuilder {
|
||||
private final boolean isSupported;
|
||||
private final Set<LobTypes> supportedTypes;
|
||||
|
||||
private JdbcLobBuilderImpl(boolean isSupported) {
|
||||
this.isSupported = isSupported;
|
||||
private JdbcLobBuilderImpl(LobTypes... supportedTypes) {
|
||||
this.supportedTypes = convert( supportedTypes );
|
||||
}
|
||||
|
||||
private static Set<LobTypes> convert(LobTypes... supportedTypes) {
|
||||
final Set<LobTypes> result = new HashSet<>();
|
||||
result.addAll( Arrays.asList( supportedTypes ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
public Blob createBlob() throws SQLException {
|
||||
if ( ! isSupported ) {
|
||||
if ( ! supportedTypes.contains( LobTypes.BLOB ) ) {
|
||||
throw new SQLException( "not supported!" );
|
||||
}
|
||||
return new JdbcBlob();
|
||||
}
|
||||
|
||||
public Clob createClob() throws SQLException {
|
||||
if ( ! isSupported ) {
|
||||
if ( ! supportedTypes.contains( LobTypes.CLOB ) ) {
|
||||
throw new SQLException( "not supported!" );
|
||||
}
|
||||
return new JdbcClob();
|
||||
}
|
||||
|
||||
public NClob createNClob() throws SQLException {
|
||||
if ( ! isSupported ) {
|
||||
if ( ! supportedTypes.contains( LobTypes.NCLOB ) ) {
|
||||
throw new SQLException( "not supported!" );
|
||||
}
|
||||
return new JdbcNClob();
|
||||
|
|
|
@ -29,11 +29,16 @@ import jakarta.persistence.Lob;
|
|||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.orm.junit.Jira;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
@ -102,6 +107,9 @@ public class LobUnfetchedPropertyTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
@RequiresDialectFeature(DialectChecks.SupportsNClob.class)
|
||||
@SkipForDialect(
|
||||
dialectClass = SybaseDialect.class, matchSubTypes = true,
|
||||
reason = "jConnect does not support Connection#createNClob which is ultimately used by LobHelper#createNClob" )
|
||||
public void testNClob() {
|
||||
final int id = doInHibernate( this::sessionFactory, s -> {
|
||||
FileNClob file = new FileNClob();
|
||||
|
@ -219,4 +227,34 @@ public class LobUnfetchedPropertyTest extends BaseCoreFunctionalTestCase {
|
|||
this.clob = clob;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "FileNClob2")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, includeLazy = false)
|
||||
public static class FileNClob2 {
|
||||
|
||||
private int id;
|
||||
|
||||
private String clob;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Column(name = "filedata", length = 1024 * 1024)
|
||||
@Lob
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
public String getClob() {
|
||||
return clob;
|
||||
}
|
||||
|
||||
public void setClob(String clob) {
|
||||
this.clob = clob;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue