HHH-9724 - More complete "temp table" coverage and allow Dialects to influence which strategy is used - initial work
This commit is contained in:
parent
7ca12c7d80
commit
06b6135a11
|
@ -585,15 +585,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilder {
|
|||
configurationSettings.get( MULTI_TENANT_IDENTIFIER_RESOLVER )
|
||||
);
|
||||
|
||||
this.multiTableBulkIdStrategy = strategySelector.resolveStrategy(
|
||||
this.multiTableBulkIdStrategy = strategySelector.resolveDefaultableStrategy(
|
||||
MultiTableBulkIdStrategy.class,
|
||||
configurationSettings.get( HQL_BULK_ID_STRATEGY )
|
||||
configurationSettings.get( HQL_BULK_ID_STRATEGY ),
|
||||
jdbcServices.getJdbcEnvironment().getDialect().getDefaultMultiTableBulkIdStrategy()
|
||||
);
|
||||
if ( this.multiTableBulkIdStrategy == null ) {
|
||||
this.multiTableBulkIdStrategy = jdbcServices.getDialect().supportsTemporaryTables()
|
||||
? TemporaryTableBulkIdStrategy.INSTANCE
|
||||
: new PersistentTableBulkIdStrategy();
|
||||
}
|
||||
|
||||
this.batchFetchStyle = BatchFetchStyle.interpret( configurationSettings.get( BATCH_FETCH_STYLE ) );
|
||||
this.defaultBatchFetchSize = ConfigurationHelper.getInt( DEFAULT_BATCH_FETCH_SIZE, configurationSettings, -1 );
|
||||
|
|
|
@ -97,6 +97,8 @@ import org.hibernate.event.internal.EntityCopyAllowedLoggedObserver;
|
|||
import org.hibernate.event.internal.EntityCopyAllowedObserver;
|
||||
import org.hibernate.event.internal.EntityCopyNotAllowedObserver;
|
||||
import org.hibernate.event.spi.EntityCopyObserver;
|
||||
import org.hibernate.hql.spi.GlobalTemporaryTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.LocalTemporaryTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.PersistentTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.TemporaryTableBulkIdStrategy;
|
||||
|
@ -371,6 +373,16 @@ public class StrategySelectorBuilder {
|
|||
PersistentTableBulkIdStrategy.SHORT_NAME,
|
||||
PersistentTableBulkIdStrategy.class
|
||||
);
|
||||
strategySelector.registerStrategyImplementor(
|
||||
MultiTableBulkIdStrategy.class,
|
||||
GlobalTemporaryTableBulkIdStrategy.SHORT_NAME,
|
||||
GlobalTemporaryTableBulkIdStrategy.class
|
||||
);
|
||||
strategySelector.registerStrategyImplementor(
|
||||
MultiTableBulkIdStrategy.class,
|
||||
LocalTemporaryTableBulkIdStrategy.SHORT_NAME,
|
||||
LocalTemporaryTableBulkIdStrategy.class
|
||||
);
|
||||
strategySelector.registerStrategyImplementor(
|
||||
MultiTableBulkIdStrategy.class,
|
||||
TemporaryTableBulkIdStrategy.SHORT_NAME,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
|
|
@ -58,6 +58,9 @@ import org.hibernate.exception.spi.ConversionContext;
|
|||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.exception.spi.SQLExceptionConverter;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
|
||||
import org.hibernate.hql.spi.LocalTemporaryTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.PersistentTableBulkIdStrategy;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.SequenceGenerator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
|
@ -1516,6 +1519,13 @@ public abstract class Dialect implements ConversionContext {
|
|||
|
||||
// temporary table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() {
|
||||
// mimic the old behavior for now...
|
||||
return supportsTemporaryTables()
|
||||
? LocalTemporaryTableBulkIdStrategy.INSTANCE
|
||||
: new PersistentTableBulkIdStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this dialect support temporary tables?
|
||||
*
|
||||
|
|
|
@ -49,6 +49,8 @@ import org.hibernate.exception.LockTimeoutException;
|
|||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
|
||||
import org.hibernate.hql.spi.GlobalTemporaryTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
|
||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||
|
@ -582,6 +584,11 @@ public class Oracle8iDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() {
|
||||
return new GlobalTemporaryTableBulkIdStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemporaryTables() {
|
||||
return true;
|
||||
|
|
|
@ -37,6 +37,8 @@ import org.hibernate.dialect.function.StandardSQLFunction;
|
|||
import org.hibernate.dialect.function.VarArgsSQLFunction;
|
||||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
|
||||
import org.hibernate.hql.spi.GlobalTemporaryTableBulkIdStrategy;
|
||||
import org.hibernate.hql.spi.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
@ -351,6 +353,11 @@ public class Oracle9Dialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() {
|
||||
return new GlobalTemporaryTableBulkIdStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemporaryTables() {
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
||||
/**
|
||||
* Strategy based on ANSI SQL's definition of a "global temporary table".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GlobalTemporaryTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
||||
public static final String CLEAN_UP_ID_TABLES = "hibernate.hql.bulk_id_strategy.global_temporary.clean_up";
|
||||
|
||||
public static final String SHORT_NAME = "global_temporary";
|
||||
|
||||
private boolean cleanUpTables;
|
||||
private List<String> tableCleanUpDdl;
|
||||
|
||||
@Override
|
||||
public void prepare(
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess connectionAccess,
|
||||
MetadataImplementor metadata) {
|
||||
final ConfigurationService configService = metadata.getMetadataBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.getService( ConfigurationService.class );
|
||||
this.cleanUpTables = configService.getSetting(
|
||||
CLEAN_UP_ID_TABLES,
|
||||
StandardConverters.BOOLEAN,
|
||||
false
|
||||
);
|
||||
|
||||
final List<Table> idTableDefinitions = new ArrayList<Table>();
|
||||
|
||||
for ( PersistentClass entityBinding : metadata.getEntityBindings() ) {
|
||||
if ( !MultiTableBulkIdHelper.INSTANCE.needsIdTable( entityBinding ) ) {
|
||||
continue;
|
||||
}
|
||||
final Table idTableDefinition = generateIdTableDefinition( entityBinding, metadata );
|
||||
idTableDefinitions.add( idTableDefinition );
|
||||
|
||||
if ( cleanUpTables ) {
|
||||
if ( tableCleanUpDdl == null ) {
|
||||
tableCleanUpDdl = new ArrayList<String>();
|
||||
}
|
||||
tableCleanUpDdl.add( idTableDefinition.sqlDropString( jdbcServices.getDialect(), null, null ) );
|
||||
}
|
||||
}
|
||||
|
||||
// we export them all at once to better reuse JDBC resources
|
||||
exportTableDefinitions( idTableDefinitions, jdbcServices, connectionAccess, metadata );
|
||||
}
|
||||
|
||||
protected Table generateIdTableDefinition(PersistentClass entityMapping, MetadataImplementor metadata) {
|
||||
return MultiTableBulkIdHelper.INSTANCE.generateIdTableDefinition(
|
||||
entityMapping,
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
protected void exportTableDefinitions(
|
||||
List<Table> idTableDefinitions,
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess connectionAccess,
|
||||
MetadataImplementor metadata) {
|
||||
MultiTableBulkIdHelper.INSTANCE.exportTableDefinitions(
|
||||
idTableDefinitions,
|
||||
jdbcServices,
|
||||
connectionAccess,
|
||||
metadata
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
if ( ! cleanUpTables ) {
|
||||
return;
|
||||
}
|
||||
|
||||
MultiTableBulkIdHelper.INSTANCE.cleanupTableDefinitions( jdbcServices, connectionAccess, tableCleanUpDdl );
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateHandler buildUpdateHandler(
|
||||
SessionFactoryImplementor factory, HqlSqlWalker walker) {
|
||||
return new TableBasedUpdateHandlerImpl( factory, walker ) {
|
||||
@Override
|
||||
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
|
||||
// clean up our id-table rows
|
||||
cleanUpRows( determineIdTableName( persister ), session );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void cleanUpRows(String tableName, SessionImplementor session) {
|
||||
final String sql = "delete from " + tableName;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
|
||||
}
|
||||
finally {
|
||||
if ( ps != null ) {
|
||||
try {
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().release( ps );
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteHandler buildDeleteHandler(
|
||||
SessionFactoryImplementor factory, HqlSqlWalker walker) {
|
||||
return new TableBasedDeleteHandlerImpl( factory, walker ) {
|
||||
@Override
|
||||
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
|
||||
// clean up our id-table rows
|
||||
cleanUpRows( determineIdTableName( persister ), session );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jdbc.AbstractWork;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Strategy based on ANSI SQL's definition of a "local temporary table" (local to each db session).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalTemporaryTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
||||
public static final LocalTemporaryTableBulkIdStrategy INSTANCE = new LocalTemporaryTableBulkIdStrategy();
|
||||
|
||||
public static final String SHORT_NAME = "temporary";
|
||||
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
LocalTemporaryTableBulkIdStrategy.class.getName()
|
||||
);
|
||||
|
||||
@Override
|
||||
public void prepare(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
|
||||
return new TableBasedUpdateHandlerImpl( factory, walker ) {
|
||||
@Override
|
||||
protected void prepareForUse(Queryable persister, SessionImplementor session) {
|
||||
createTempTable( persister, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
|
||||
releaseTempTable( persister, session );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
|
||||
return new TableBasedDeleteHandlerImpl( factory, walker ) {
|
||||
@Override
|
||||
protected void prepareForUse(Queryable persister, SessionImplementor session) {
|
||||
createTempTable( persister, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
|
||||
releaseTempTable( persister, session );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected void createTempTable(Queryable persister, SessionImplementor session) {
|
||||
// Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
|
||||
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
|
||||
TemporaryTableCreationWork work = new TemporaryTableCreationWork( persister );
|
||||
if ( shouldIsolateTemporaryTableDDL( session ) ) {
|
||||
session.getTransactionCoordinator()
|
||||
.getTransaction()
|
||||
.createIsolationDelegate()
|
||||
.delegateWork( work, shouldTransactIsolatedTemporaryTableDDL( session ) );
|
||||
}
|
||||
else {
|
||||
final Connection connection = session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getConnection();
|
||||
work.execute( connection );
|
||||
session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.afterStatementExecution();
|
||||
}
|
||||
}
|
||||
|
||||
protected void releaseTempTable(Queryable persister, SessionImplementor session) {
|
||||
if ( session.getFactory().getDialect().dropTemporaryTableAfterUse() ) {
|
||||
TemporaryTableDropWork work = new TemporaryTableDropWork( persister, session );
|
||||
if ( shouldIsolateTemporaryTableDDL( session ) ) {
|
||||
session.getTransactionCoordinator()
|
||||
.getTransaction()
|
||||
.createIsolationDelegate()
|
||||
.delegateWork( work, shouldTransactIsolatedTemporaryTableDDL( session ) );
|
||||
}
|
||||
else {
|
||||
final Connection connection = session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getConnection();
|
||||
work.execute( connection );
|
||||
session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.afterStatementExecution();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// at the very least cleanup the data :)
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
final String sql = "delete from " + persister.getTemporaryIdTableName();
|
||||
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.unableToCleanupTemporaryIdTable(t);
|
||||
}
|
||||
finally {
|
||||
if ( ps != null ) {
|
||||
try {
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().release( ps );
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldIsolateTemporaryTableDDL(SessionImplementor session) {
|
||||
Boolean dialectVote = session.getFactory().getDialect().performTemporaryTableDDLInIsolation();
|
||||
if ( dialectVote != null ) {
|
||||
return dialectVote;
|
||||
}
|
||||
return session.getFactory().getSettings().isDataDefinitionImplicitCommit();
|
||||
}
|
||||
|
||||
protected boolean shouldTransactIsolatedTemporaryTableDDL(SessionImplementor session) {
|
||||
// is there ever a time when it makes sense to do this?
|
||||
// return session.getFactory().getSettings().isDataDefinitionInTransactionSupported();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class TemporaryTableCreationWork extends AbstractWork {
|
||||
private final Queryable persister;
|
||||
|
||||
private TemporaryTableCreationWork(Queryable persister) {
|
||||
this.persister = persister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Connection connection) {
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
try {
|
||||
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
|
||||
persister.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getSqlExceptionHelper()
|
||||
.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SqlExceptionHelper.WarningHandler CREATION_WARNING_HANDLER = new SqlExceptionHelper.WarningHandlerLoggingSupport() {
|
||||
public boolean doProcess() {
|
||||
return log.isDebugEnabled();
|
||||
}
|
||||
|
||||
public void prepare(SQLWarning warning) {
|
||||
log.warningsCreatingTempTable( warning );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void logWarning(String description, String message) {
|
||||
log.debug( description );
|
||||
log.debug( message );
|
||||
}
|
||||
};
|
||||
|
||||
private static class TemporaryTableDropWork extends AbstractWork {
|
||||
private final Queryable persister;
|
||||
private final SessionImplementor session;
|
||||
|
||||
private TemporaryTableDropWork(Queryable persister, SessionImplementor session) {
|
||||
this.persister = persister;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Connection connection) {
|
||||
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
|
||||
+ ' ' + persister.getTemporaryIdTableName();
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
try {
|
||||
statement.executeUpdate( command );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
log.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.JoinedSubclass;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UnionSubclass;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MultiTableBulkIdHelper {
|
||||
private static final Logger log = Logger.getLogger( MultiTableBulkIdHelper.class );
|
||||
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final MultiTableBulkIdHelper INSTANCE = new MultiTableBulkIdHelper();
|
||||
|
||||
private MultiTableBulkIdHelper() {
|
||||
}
|
||||
|
||||
public boolean needsIdTable(PersistentClass entityBinding) {
|
||||
// need id table if the entity has secondary tables (joins)
|
||||
if ( entityBinding.getJoinClosureSpan() > 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// need an id table if the entity is part of either a JOINED or UNION inheritance
|
||||
// hierarchy. We do not allow inheritance strategy mixing, so work on that assumption
|
||||
// here...
|
||||
final RootClass rootEntityBinding = entityBinding.getRootClass();
|
||||
final Iterator itr = rootEntityBinding.getSubclassIterator();
|
||||
if ( itr.hasNext() ) {
|
||||
final Subclass subclassEntityBinding = (Subclass) itr.next();
|
||||
if ( subclassEntityBinding instanceof JoinedSubclass || subclassEntityBinding instanceof UnionSubclass ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public Table generateIdTableDefinition(
|
||||
PersistentClass entityMapping,
|
||||
String catalog,
|
||||
String schema,
|
||||
boolean generateSessionIdColumn) {
|
||||
Table idTable = new Table( entityMapping.getTemporaryIdTableName() );
|
||||
idTable.setComment( "Used to hold id values for the " + entityMapping.getEntityName() + " class" );
|
||||
|
||||
if ( catalog != null ) {
|
||||
idTable.setCatalog( catalog );
|
||||
}
|
||||
if ( schema != null ) {
|
||||
idTable.setSchema( schema );
|
||||
}
|
||||
|
||||
Iterator itr = entityMapping.getTable().getPrimaryKey().getColumnIterator();
|
||||
while( itr.hasNext() ) {
|
||||
Column column = (Column) itr.next();
|
||||
idTable.addColumn( column.clone() );
|
||||
}
|
||||
|
||||
if ( generateSessionIdColumn ) {
|
||||
Column sessionIdColumn = new Column( "hib_sess_id" );
|
||||
sessionIdColumn.setSqlType( "CHAR(36)" );
|
||||
sessionIdColumn.setComment( "Used to hold the Hibernate Session identifier" );
|
||||
idTable.addColumn( sessionIdColumn );
|
||||
}
|
||||
|
||||
return idTable;
|
||||
}
|
||||
|
||||
protected void exportTableDefinitions(
|
||||
List<Table> idTableDefinitions,
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess connectionAccess,
|
||||
MetadataImplementor metadata) {
|
||||
try {
|
||||
Connection connection;
|
||||
try {
|
||||
connection = connectionAccess.obtainConnection();
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
// assume this comes from org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl
|
||||
log.debug( "Unable to obtain JDBC connection; assuming ID tables already exist or wont be needed" );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().createStatement();
|
||||
Statement statement = connection.createStatement();
|
||||
for ( Table idTableDefinition : idTableDefinitions ) {
|
||||
try {
|
||||
final String sql = idTableDefinition.sqlCreateString( jdbcServices.getDialect(), metadata, null, null );
|
||||
jdbcServices.getSqlStatementLogger().logStatement( sql );
|
||||
// TODO: ResultSetExtractor
|
||||
statement.execute( sql );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debugf( "Error attempting to export id-table [%s] : %s", idTableDefinition.getName(), e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// session.getTransactionCoordinator().getJdbcCoordinator().release( statement );
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable to use JDBC Connection to create Statement", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connectionAccess.releaseConnection( connection );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable obtain JDBC Connection", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupTableDefinitions(
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess connectionAccess,
|
||||
List<String> tableCleanUpDdl) {
|
||||
if ( tableCleanUpDdl == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Connection connection = connectionAccess.obtainConnection();
|
||||
|
||||
try {
|
||||
// TODO: session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().createStatement();
|
||||
Statement statement = connection.createStatement();
|
||||
|
||||
for ( String cleanupDdl : tableCleanUpDdl ) {
|
||||
try {
|
||||
jdbcServices.getSqlStatementLogger().logStatement( cleanupDdl );
|
||||
statement.execute( cleanupDdl );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debugf( "Error attempting to cleanup id-table : [%s]", e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// session.getTransactionCoordinator().getJdbcCoordinator().release( statement );
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable to use JDBC Connection to create Statement", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connectionAccess.releaseConnection( connection );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable obtain JDBC Connection", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,13 +23,10 @@
|
|||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -45,7 +42,6 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
||||
import org.hibernate.internal.AbstractSessionImpl;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
@ -55,6 +51,10 @@ import org.hibernate.type.UUIDCharType;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* This is a strategy that mimics temporary tables for databases which do not support
|
||||
* temporary tables. It follows a pattern similar to the ANSI SQL definition of global
|
||||
* temporary table using a "session id" column to segment rows from the various sessions.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PersistentTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
||||
|
@ -74,6 +74,13 @@ public class PersistentTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
|||
private boolean cleanUpTables;
|
||||
private List<String> tableCleanUpDdl;
|
||||
|
||||
/**
|
||||
* Creates the tables for all the entities that might need it
|
||||
*
|
||||
* @param jdbcServices The JdbcService object
|
||||
* @param connectionAccess Access to the JDBC Connection
|
||||
* @param metadata Access to the O/RM mapping information
|
||||
*/
|
||||
@Override
|
||||
public void prepare(
|
||||
JdbcServices jdbcServices,
|
||||
|
@ -101,32 +108,31 @@ public class PersistentTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
|||
final List<Table> idTableDefinitions = new ArrayList<Table>();
|
||||
|
||||
for ( PersistentClass entityBinding : metadata.getEntityBindings() ) {
|
||||
if ( !MultiTableBulkIdHelper.INSTANCE.needsIdTable( entityBinding ) ) {
|
||||
continue;
|
||||
}
|
||||
final Table idTableDefinition = generateIdTableDefinition( entityBinding, metadata );
|
||||
idTableDefinitions.add( idTableDefinition );
|
||||
|
||||
if ( cleanUpTables ) {
|
||||
if ( tableCleanUpDdl == null ) {
|
||||
tableCleanUpDdl = new ArrayList<String>();
|
||||
}
|
||||
tableCleanUpDdl.add( idTableDefinition.sqlDropString( jdbcServices.getDialect(), null, null ) );
|
||||
}
|
||||
}
|
||||
|
||||
// we export them all at once to better reuse JDBC resources
|
||||
exportTableDefinitions( idTableDefinitions, jdbcServices, connectionAccess, metadata );
|
||||
}
|
||||
|
||||
protected Table generateIdTableDefinition(PersistentClass entityMapping, MetadataImplementor metadata) {
|
||||
Table idTable = new Table( entityMapping.getTemporaryIdTableName() );
|
||||
if ( catalog != null ) {
|
||||
idTable.setCatalog( catalog );
|
||||
}
|
||||
if ( schema != null ) {
|
||||
idTable.setSchema( schema );
|
||||
}
|
||||
Iterator itr = entityMapping.getTable().getPrimaryKey().getColumnIterator();
|
||||
while( itr.hasNext() ) {
|
||||
Column column = (Column) itr.next();
|
||||
idTable.addColumn( column.clone() );
|
||||
}
|
||||
Column sessionIdColumn = new Column( "hib_sess_id" );
|
||||
sessionIdColumn.setSqlType( "CHAR(36)" );
|
||||
sessionIdColumn.setComment( "Used to hold the Hibernate Session identifier" );
|
||||
idTable.addColumn( sessionIdColumn );
|
||||
|
||||
idTable.setComment( "Used to hold id values for the " + entityMapping.getEntityName() + " class" );
|
||||
return idTable;
|
||||
return MultiTableBulkIdHelper.INSTANCE.generateIdTableDefinition(
|
||||
entityMapping,
|
||||
catalog,
|
||||
schema,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
protected void exportTableDefinitions(
|
||||
|
@ -134,99 +140,21 @@ public class PersistentTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
|||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess connectionAccess,
|
||||
MetadataImplementor metadata) {
|
||||
try {
|
||||
Connection connection;
|
||||
try {
|
||||
connection = connectionAccess.obtainConnection();
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
// assume this comes from org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl
|
||||
log.debug( "Unable to obtain JDBC connection; assuming ID tables already exist or wont be needed" );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().createStatement();
|
||||
Statement statement = connection.createStatement();
|
||||
for ( Table idTableDefinition : idTableDefinitions ) {
|
||||
if ( cleanUpTables ) {
|
||||
if ( tableCleanUpDdl == null ) {
|
||||
tableCleanUpDdl = new ArrayList<String>();
|
||||
}
|
||||
tableCleanUpDdl.add( idTableDefinition.sqlDropString( jdbcServices.getDialect(), null, null ) );
|
||||
}
|
||||
try {
|
||||
final String sql = idTableDefinition.sqlCreateString( jdbcServices.getDialect(), metadata, null, null );
|
||||
jdbcServices.getSqlStatementLogger().logStatement( sql );
|
||||
// TODO: ResultSetExtractor
|
||||
statement.execute( sql );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debugf( "Error attempting to export id-table [%s] : %s", idTableDefinition.getName(), e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// session.getTransactionCoordinator().getJdbcCoordinator().release( statement );
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable to use JDBC Connection to create Statement", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connectionAccess.releaseConnection( connection );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable obtain JDBC Connection", e );
|
||||
}
|
||||
MultiTableBulkIdHelper.INSTANCE.exportTableDefinitions(
|
||||
idTableDefinitions,
|
||||
jdbcServices,
|
||||
connectionAccess,
|
||||
metadata
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) {
|
||||
if ( ! cleanUpTables || tableCleanUpDdl == null ) {
|
||||
if ( ! cleanUpTables ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Connection connection = connectionAccess.obtainConnection();
|
||||
|
||||
try {
|
||||
// TODO: session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().createStatement();
|
||||
Statement statement = connection.createStatement();
|
||||
|
||||
for ( String cleanupDdl : tableCleanUpDdl ) {
|
||||
try {
|
||||
jdbcServices.getSqlStatementLogger().logStatement( cleanupDdl );
|
||||
statement.execute( cleanupDdl );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debugf( "Error attempting to cleanup id-table : [%s]", e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// session.getTransactionCoordinator().getJdbcCoordinator().release( statement );
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable to use JDBC Connection to create Statement", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connectionAccess.releaseConnection( connection );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable obtain JDBC Connection", e );
|
||||
}
|
||||
MultiTableBulkIdHelper.INSTANCE.cleanupTableDefinitions( jdbcServices, connectionAccess, tableCleanUpDdl );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,239 +23,42 @@
|
|||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jdbc.AbstractWork;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*
|
||||
* @deprecated Use the more specific {@link org.hibernate.hql.spi.LocalTemporaryTableBulkIdStrategy} instead.
|
||||
*/
|
||||
public class TemporaryTableBulkIdStrategy implements MultiTableBulkIdStrategy {
|
||||
@Deprecated
|
||||
public class TemporaryTableBulkIdStrategy extends LocalTemporaryTableBulkIdStrategy {
|
||||
public static final TemporaryTableBulkIdStrategy INSTANCE = new TemporaryTableBulkIdStrategy();
|
||||
|
||||
public static final String SHORT_NAME = "temporary";
|
||||
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
TemporaryTableBulkIdStrategy.class.getName()
|
||||
);
|
||||
|
||||
@Override
|
||||
public void prepare(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata) {
|
||||
// nothing to do
|
||||
DeprecationLogger.DEPRECATION_LOGGER.logDeprecationOfTemporaryTableBulkIdStrategy();
|
||||
super.prepare( jdbcServices, connectionAccess, metadata );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) {
|
||||
// nothing to do
|
||||
super.release( jdbcServices, connectionAccess );
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
|
||||
return new TableBasedUpdateHandlerImpl( factory, walker ) {
|
||||
@Override
|
||||
protected void prepareForUse(Queryable persister, SessionImplementor session) {
|
||||
createTempTable( persister, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
|
||||
releaseTempTable( persister, session );
|
||||
}
|
||||
};
|
||||
return super.buildUpdateHandler( factory, walker );
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
|
||||
return new TableBasedDeleteHandlerImpl( factory, walker ) {
|
||||
@Override
|
||||
protected void prepareForUse(Queryable persister, SessionImplementor session) {
|
||||
createTempTable( persister, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
|
||||
releaseTempTable( persister, session );
|
||||
}
|
||||
};
|
||||
return super.buildDeleteHandler( factory, walker );
|
||||
}
|
||||
|
||||
|
||||
protected void createTempTable(Queryable persister, SessionImplementor session) {
|
||||
// Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
|
||||
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
|
||||
TemporaryTableCreationWork work = new TemporaryTableCreationWork( persister );
|
||||
if ( shouldIsolateTemporaryTableDDL( session ) ) {
|
||||
session.getTransactionCoordinator()
|
||||
.getTransaction()
|
||||
.createIsolationDelegate()
|
||||
.delegateWork( work, shouldTransactIsolatedTemporaryTableDDL( session ) );
|
||||
}
|
||||
else {
|
||||
final Connection connection = session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getConnection();
|
||||
work.execute( connection );
|
||||
session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.afterStatementExecution();
|
||||
}
|
||||
}
|
||||
|
||||
protected void releaseTempTable(Queryable persister, SessionImplementor session) {
|
||||
if ( session.getFactory().getDialect().dropTemporaryTableAfterUse() ) {
|
||||
TemporaryTableDropWork work = new TemporaryTableDropWork( persister, session );
|
||||
if ( shouldIsolateTemporaryTableDDL( session ) ) {
|
||||
session.getTransactionCoordinator()
|
||||
.getTransaction()
|
||||
.createIsolationDelegate()
|
||||
.delegateWork( work, shouldTransactIsolatedTemporaryTableDDL( session ) );
|
||||
}
|
||||
else {
|
||||
final Connection connection = session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getConnection();
|
||||
work.execute( connection );
|
||||
session.getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.afterStatementExecution();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// at the very least cleanup the data :)
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
final String sql = "delete from " + persister.getTemporaryIdTableName();
|
||||
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.unableToCleanupTemporaryIdTable(t);
|
||||
}
|
||||
finally {
|
||||
if ( ps != null ) {
|
||||
try {
|
||||
session.getTransactionCoordinator().getJdbcCoordinator().release( ps );
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldIsolateTemporaryTableDDL(SessionImplementor session) {
|
||||
Boolean dialectVote = session.getFactory().getDialect().performTemporaryTableDDLInIsolation();
|
||||
if ( dialectVote != null ) {
|
||||
return dialectVote;
|
||||
}
|
||||
return session.getFactory().getSettings().isDataDefinitionImplicitCommit();
|
||||
}
|
||||
|
||||
protected boolean shouldTransactIsolatedTemporaryTableDDL(SessionImplementor session) {
|
||||
// is there ever a time when it makes sense to do this?
|
||||
// return session.getFactory().getSettings().isDataDefinitionInTransactionSupported();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class TemporaryTableCreationWork extends AbstractWork {
|
||||
private final Queryable persister;
|
||||
|
||||
private TemporaryTableCreationWork(Queryable persister) {
|
||||
this.persister = persister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Connection connection) {
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
try {
|
||||
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
|
||||
persister.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getSqlExceptionHelper()
|
||||
.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SqlExceptionHelper.WarningHandler CREATION_WARNING_HANDLER = new SqlExceptionHelper.WarningHandlerLoggingSupport() {
|
||||
public boolean doProcess() {
|
||||
return log.isDebugEnabled();
|
||||
}
|
||||
|
||||
public void prepare(SQLWarning warning) {
|
||||
log.warningsCreatingTempTable( warning );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void logWarning(String description, String message) {
|
||||
log.debug( description );
|
||||
log.debug( message );
|
||||
}
|
||||
};
|
||||
|
||||
private static class TemporaryTableDropWork extends AbstractWork {
|
||||
private final Queryable persister;
|
||||
private final SessionImplementor session;
|
||||
|
||||
private TemporaryTableDropWork(Queryable persister, SessionImplementor session) {
|
||||
this.persister = persister;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Connection connection) {
|
||||
final String command = session.getFactory().getDialect().getDropTemporaryTableString()
|
||||
+ ' ' + persister.getTemporaryIdTableName();
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
try {
|
||||
statement.executeUpdate( command );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
log.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -151,4 +151,13 @@ public interface DeprecationLogger {
|
|||
id = 90000010
|
||||
)
|
||||
void deprecatedManyToManyFetch();
|
||||
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
value = "org.hibernate.hql.spi.TemporaryTableBulkIdStrategy (temporary) has been deprecated in favor of the" +
|
||||
" more specific org.hibernate.hql.spi.LocalTemporaryTableBulkIdStrategy (local_temporary).",
|
||||
id = 90000010
|
||||
)
|
||||
void logDeprecationOfTemporaryTableBulkIdStrategy();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue