diff --git a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java index d711e5c1bd..ca53d8010d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java @@ -37,8 +37,7 @@ import org.hibernate.cache.spi.QueryCacheFactory; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.dialect.function.SQLFunction; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; -import org.hibernate.hql.spi.QueryTranslatorFactory; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.loader.BatchFetchStyle; import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.tuple.entity.EntityTuplizer; @@ -266,6 +265,8 @@ public SessionFactoryBuilder applyEntityTuplizer( */ public SessionFactoryBuilder applyMultiTableBulkIdStrategy(MultiTableBulkIdStrategy strategy); + public SessionFactoryBuilder applyTempTableDdlTransactionHandling(TempTableDdlTransactionHandling handling); + /** * What style of batching should be used? * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/TempTableDdlTransactionHandling.java b/hibernate-core/src/main/java/org/hibernate/boot/TempTableDdlTransactionHandling.java new file mode 100644 index 0000000000..ac1454fb2f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/TempTableDdlTransactionHandling.java @@ -0,0 +1,47 @@ +/* + * 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.boot; + +/** + * Enum describing how creation and dropping of temporary tables should be done in terms of + * transaction handling. + * + * @author Steve Ebersole + */ +public enum TempTableDdlTransactionHandling { + /** + * No handling of transactions is needed + */ + NONE, + /** + * Execution of the DDL must be isolated from any ongoing transaction + */ + ISOLATE, + /** + * As with {@link #ISOLATE} the execution of the DDL must be isolated from any ongoing transaction. + * However, here the "isolation" will also be transacted. Some databases require that the DDL + * happen within a transaction. This value covers such cases. + */ + ISOLATE_AND_TRANSACT +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java index edab8785b4..2f5db38c89 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java @@ -43,6 +43,7 @@ import org.hibernate.SessionFactoryObserver; import org.hibernate.boot.SchemaAutoTooling; import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.boot.spi.MetadataImplementor; @@ -60,7 +61,7 @@ import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.transaction.spi.TransactionFactory; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.loader.BatchFetchStyle; @@ -251,6 +252,12 @@ public SessionFactoryBuilder applyMultiTableBulkIdStrategy(MultiTableBulkIdStrat return this; } + @Override + public SessionFactoryBuilder applyTempTableDdlTransactionHandling(TempTableDdlTransactionHandling handling) { + this.options.tempTableDdlTransactionHandling = handling; + return this; + } + @Override public SessionFactoryBuilder applyBatchFetchStyle(BatchFetchStyle style) { this.options.batchFetchStyle = style; @@ -481,6 +488,7 @@ public static class SessionFactoryOptionsStateStandardImpl implements SessionFac private boolean checkNullability; private boolean initializeLazyStateOutsideTransactions; private MultiTableBulkIdStrategy multiTableBulkIdStrategy; + private TempTableDdlTransactionHandling tempTableDdlTransactionHandling; private BatchFetchStyle batchFetchStyle; private int defaultBatchFetchSize; private Integer maximumFetchDepth; @@ -514,8 +522,6 @@ public static class SessionFactoryOptionsStateStandardImpl implements SessionFac private SchemaAutoTooling schemaAutoTooling; // JDBC Handling - private boolean dataDefinitionImplicitCommit; // not exposed on builder atm - private boolean dataDefinitionInTransactionSupported; // not exposed on builder atm private boolean getGeneratedKeysEnabled; private int jdbcBatchSize; private boolean jdbcBatchVersionedData; @@ -641,8 +647,16 @@ public SessionFactoryOptionsStateStandardImpl(StandardServiceRegistry serviceReg final ExtractedDatabaseMetaData meta = jdbcServices.getExtractedMetaDataSupport(); - this.dataDefinitionImplicitCommit = meta.doesDataDefinitionCauseTransactionCommit(); - this.dataDefinitionInTransactionSupported = meta.supportsDataDefinitionInTransaction(); + + this.tempTableDdlTransactionHandling = TempTableDdlTransactionHandling.NONE; + if ( meta.doesDataDefinitionCauseTransactionCommit() ) { + if ( meta.supportsDataDefinitionInTransaction() ) { + this.tempTableDdlTransactionHandling = TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT; + } + else { + this.tempTableDdlTransactionHandling = TempTableDdlTransactionHandling.ISOLATE; + } + } this.jdbcBatchSize = ConfigurationHelper.getInt( STATEMENT_BATCH_SIZE, configurationSettings, 0 ); if ( !meta.supportsBatchUpdates() ) { @@ -763,6 +777,11 @@ public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy() { return multiTableBulkIdStrategy; } + @Override + public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling() { + return tempTableDdlTransactionHandling; + } + @Override public BatchFetchStyle getBatchFetchStyle() { return batchFetchStyle; @@ -868,16 +887,6 @@ public SchemaAutoTooling getSchemaAutoTooling() { return schemaAutoTooling; } - @Override - public boolean isDataDefinitionImplicitCommit() { - return dataDefinitionImplicitCommit; - } - - @Override - public boolean isDataDefinitionInTransactionSupported() { - return dataDefinitionInTransactionSupported; - } - @Override public int getJdbcBatchSize() { return jdbcBatchSize; @@ -1025,6 +1034,11 @@ public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy() { return options.getMultiTableBulkIdStrategy(); } + @Override + public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling() { + return options.getTempTableDdlTransactionHandling(); + } + @Override public BatchFetchStyle getBatchFetchStyle() { return options.getBatchFetchStyle(); @@ -1130,16 +1144,6 @@ public SchemaAutoTooling getSchemaAutoTooling() { return options.getSchemaAutoTooling(); } - @Override - public boolean isDataDefinitionImplicitCommit() { - return options.isDataDefinitionImplicitCommit(); - } - - @Override - public boolean isDataDefinitionInTransactionSupported() { - return options.isDataDefinitionInTransactionSupported(); - } - @Override public int getJdbcBatchSize() { return options.getJdbcBatchSize(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java index 006e3768e5..fd1c96a033 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java @@ -34,13 +34,14 @@ import org.hibernate.NullPrecedence; import org.hibernate.SessionFactoryObserver; import org.hibernate.boot.SchemaAutoTooling; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.spi.QueryCacheFactory; import org.hibernate.cfg.BaselineSessionEventsListenerBuilder; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.dialect.function.SQLFunction; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.loader.BatchFetchStyle; import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.tuple.entity.EntityTuplizerFactory; @@ -81,6 +82,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { private boolean checkNullability; private final boolean initializeLazyStateOutsideTransactions; private final MultiTableBulkIdStrategy multiTableBulkIdStrategy; + private final TempTableDdlTransactionHandling tempTableDdlTransactionHandling; private final BatchFetchStyle batchFetchStyle; private final int defaultBatchFetchSize; private final Integer maximumFetchDepth; @@ -114,8 +116,6 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { private final SchemaAutoTooling schemaAutoTooling; // JDBC Handling - private final boolean dataDefinitionImplicitCommit; // not exposed on builder atm - private final boolean dataDefinitionInTransactionSupported; // not exposed on builder atm private final boolean getGeneratedKeysEnabled; private final int jdbcBatchSize; private final boolean jdbcBatchVersionedData; @@ -154,6 +154,7 @@ public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) { this.checkNullability = state.isCheckNullability(); this.initializeLazyStateOutsideTransactions = state.isInitializeLazyStateOutsideTransactionsEnabled(); this.multiTableBulkIdStrategy = state.getMultiTableBulkIdStrategy(); + this.tempTableDdlTransactionHandling = state.getTempTableDdlTransactionHandling(); this.batchFetchStyle = state.getBatchFetchStyle(); this.defaultBatchFetchSize = state.getDefaultBatchFetchSize(); this.maximumFetchDepth = state.getMaximumFetchDepth(); @@ -182,8 +183,6 @@ public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) { this.schemaAutoTooling = state.getSchemaAutoTooling(); this.connectionReleaseMode = state.getConnectionReleaseMode(); - this.dataDefinitionImplicitCommit = state.isDataDefinitionImplicitCommit(); - this.dataDefinitionInTransactionSupported = state.isDataDefinitionInTransactionSupported(); this.getGeneratedKeysEnabled = state.isGetGeneratedKeysEnabled(); this.jdbcBatchSize = state.getJdbcBatchSize(); this.jdbcBatchVersionedData = state.isJdbcBatchVersionedData(); @@ -279,6 +278,11 @@ public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy() { return multiTableBulkIdStrategy; } + @Override + public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling() { + return tempTableDdlTransactionHandling; + } + @Override public BatchFetchStyle getBatchFetchStyle() { return batchFetchStyle; @@ -383,16 +387,6 @@ public SchemaAutoTooling getSchemaAutoTooling() { return schemaAutoTooling; } - @Override - public boolean isDataDefinitionImplicitCommit() { - return dataDefinitionImplicitCommit; - } - - @Override - public boolean isDataDefinitionInTransactionSupported() { - return dataDefinitionInTransactionSupported; - } - @Override public int getJdbcBatchSize() { return jdbcBatchSize; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java index 7e4280a174..bce4250a88 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java @@ -34,12 +34,13 @@ import org.hibernate.NullPrecedence; import org.hibernate.SessionFactoryObserver; import org.hibernate.boot.SchemaAutoTooling; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.cache.spi.QueryCacheFactory; import org.hibernate.cfg.BaselineSessionEventsListenerBuilder; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.dialect.function.SQLFunction; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.loader.BatchFetchStyle; import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.tuple.entity.EntityTuplizerFactory; @@ -84,6 +85,8 @@ public interface SessionFactoryOptionsState { public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy(); + public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling(); + public BatchFetchStyle getBatchFetchStyle(); public int getDefaultBatchFetchSize(); @@ -126,10 +129,6 @@ public interface SessionFactoryOptionsState { public SchemaAutoTooling getSchemaAutoTooling(); - public boolean isDataDefinitionImplicitCommit(); - - public boolean isDataDefinitionInTransactionSupported(); - public int getJdbcBatchSize(); public boolean isJdbcBatchVersionedData(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java index 5285dfe8c2..df301da11c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java @@ -97,11 +97,10 @@ 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; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.persistent.PersistentTableBulkIdStrategy; import org.jboss.logging.Logger; @@ -383,11 +382,6 @@ private void addMultiTableBulkIdStrategies(StrategySelectorImpl strategySelector LocalTemporaryTableBulkIdStrategy.SHORT_NAME, LocalTemporaryTableBulkIdStrategy.class ); - strategySelector.registerStrategyImplementor( - MultiTableBulkIdStrategy.class, - TemporaryTableBulkIdStrategy.SHORT_NAME, - TemporaryTableBulkIdStrategy.class - ); } private void addEntityCopyObserverStrategies(StrategySelectorImpl strategySelector) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index defb08c5d5..11d741e597 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -34,12 +34,13 @@ import org.hibernate.NullPrecedence; import org.hibernate.SessionFactoryObserver; import org.hibernate.boot.SchemaAutoTooling; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.cache.spi.QueryCacheFactory; import org.hibernate.cfg.BaselineSessionEventsListenerBuilder; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.dialect.function.SQLFunction; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.loader.BatchFetchStyle; import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.tuple.entity.EntityTuplizerFactory; @@ -108,6 +109,8 @@ public interface SessionFactoryOptions { public MultiTableBulkIdStrategy getMultiTableBulkIdStrategy(); + public TempTableDdlTransactionHandling getTempTableDdlTransactionHandling(); + public BatchFetchStyle getBatchFetchStyle(); public int getDefaultBatchFetchSize(); @@ -150,10 +153,6 @@ public interface SessionFactoryOptions { public SchemaAutoTooling getSchemaAutoTooling(); - public boolean isDataDefinitionImplicitCommit(); - - public boolean isDataDefinitionInTransactionSupported(); - public int getJdbcBatchSize(); public boolean isJdbcBatchVersionedData(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java index 81715168df..b194245c84 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -36,7 +36,7 @@ import org.hibernate.cache.spi.QueryCacheFactory; import org.hibernate.cache.spi.RegionFactory; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.hql.spi.QueryTranslatorFactory; import org.hibernate.loader.BatchFetchStyle; import org.hibernate.tuple.entity.EntityTuplizerFactory; @@ -281,14 +281,6 @@ public boolean isAutoValidateSchema() { return sessionFactoryOptions.getSchemaAutoTooling() == SchemaAutoTooling.VALIDATE; } - public boolean isDataDefinitionImplicitCommit() { - return sessionFactoryOptions.isDataDefinitionImplicitCommit(); - } - - public boolean isDataDefinitionInTransactionSupported() { - return sessionFactoryOptions.isDataDefinitionInTransactionSupported(); - } - public int getJdbcBatchSize() { return sessionFactoryOptions.getJdbcBatchSize(); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java index 43b16b586c..24c185c8b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -53,6 +53,11 @@ import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.SQLGrammarException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; +import org.hibernate.hql.spi.id.IdTableSupport; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.WrapperOptions; @@ -413,8 +418,16 @@ public String getCreateSequenceString(final String sequenceName) { } @Override - public String getCreateTemporaryTableString() { - return "create global temporary table"; + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } + }, + AfterUseAction.CLEAN + ); } @Override @@ -647,11 +660,6 @@ public boolean supportsTableCheck() { return false; } - @Override - public boolean supportsTemporaryTables() { - return true; - } - @Override public boolean supportsTupleDistinctCounts() { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java index b30013b626..9886cb90bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java @@ -32,12 +32,17 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.CharIndexFunction; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.type.StandardBasicTypes; /** @@ -250,19 +255,18 @@ public String getCurrentTimestampSelectString() { } @Override - public boolean supportsTemporaryTables() { - return true; - } - - @Override - public String generateTemporaryTableName(String baseTableName) { - return "#" + baseTableName; - } - - @Override - public boolean dropTemporaryTableAfterUse() { - // sql-server, at least needed this dropped after use; strange! - return true; + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + return "#" + baseName; + } + }, + // sql-server, at least needed this dropped after use; strange! + AfterUseAction.DROP, + TempTableDdlTransactionHandling.NONE + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java index 1cfb478853..c5ff5bceac 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java @@ -53,6 +53,10 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.id.IdentityGenerator; import org.hibernate.internal.util.StringHelper; import org.hibernate.persister.entity.Lockable; @@ -458,38 +462,23 @@ public boolean hasSelfReferentialForeignKeyBug() { return true; } - - // temporary table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + final String name = super.generateIdTableName( baseName ); + return name.length() > 25 ? name.substring( 1, 25 ) : name; + } - @Override - public String generateTemporaryTableName(String baseTableName) { - final String name = super.generateTemporaryTableName( baseTableName ); - return name.length() > 25 ? name.substring( 1, 25 ) : name; - } - - @Override - public String getCreateTemporaryTableString() { - return "create global temporary table"; - } - - @Override - public Boolean performTemporaryTableDDLInIsolation() { - return Boolean.FALSE; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return ""; - } - - @Override - public boolean dropTemporaryTableAfterUse() { - return true; + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } + }, + AfterUseAction.DROP + ); } // IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index ee9cf32cd3..f4a27ef300 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -45,6 +45,10 @@ import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; @@ -403,23 +407,26 @@ public boolean supportsCommentOn() { } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + return "session." + super.generateIdTableName( baseName ); + } - @Override - public String getCreateTemporaryTableString() { - return "declare global temporary table"; - } + @Override + public String getCreateIdTableCommand() { + return "declare global temporary table"; + } - @Override - public String getCreateTemporaryTablePostfix() { - return "not logged"; - } - - @Override - public String generateTemporaryTableName(String baseTableName) { - return "session." + super.generateTemporaryTableName( baseTableName ); + @Override + public String getCreateIdTableStatementOptions() { + return "not logged"; + } + }, + AfterUseAction.CLEAN + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index cddb071ce6..0227172982 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -23,6 +23,24 @@ */ package org.hibernate.dialect; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.NClob; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -58,9 +76,8 @@ 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.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.persistent.PersistentTableBulkIdStrategy; import org.hibernate.id.IdentityGenerator; import org.hibernate.id.SequenceGenerator; import org.hibernate.id.enhanced.SequenceStyleGenerator; @@ -92,30 +109,12 @@ import org.hibernate.tool.schema.internal.StandardSequenceExporter; import org.hibernate.tool.schema.internal.StandardTableExporter; import org.hibernate.tool.schema.internal.StandardUniqueKeyExporter; -import org.hibernate.tool.schema.internal.TemporaryTableExporter; import org.hibernate.tool.schema.spi.Exporter; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; -import org.jboss.logging.Logger; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.NClob; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.Set; +import org.jboss.logging.Logger; /** * Represents a dialect of SQL implemented by a particular RDBMS. Subclasses implement Hibernate compatibility @@ -1516,100 +1515,10 @@ public String getCreateMultisetTableString() { return getCreateTableString(); } - - // temporary table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { - // mimic the old behavior for now... - return supportsTemporaryTables() - ? LocalTemporaryTableBulkIdStrategy.INSTANCE - : new PersistentTableBulkIdStrategy(); + return new PersistentTableBulkIdStrategy(); } - /** - * Does this dialect support temporary tables? - * - * @return True if temp tables are supported; false otherwise. - */ - public boolean supportsTemporaryTables() { - return false; - } - - /** - * Generate a temporary table name given the base table. - * - * @param baseTableName The table name from which to base the temp table name. - * @return The generated temp table name. - */ - public String generateTemporaryTableName(String baseTableName) { - return "HT_" + baseTableName; - } - - /** - * Command used to create a temporary table. - * - * @return The command used to create a temporary table. - */ - public String getCreateTemporaryTableString() { - return "create table"; - } - - /** - * Get any fragments needing to be postfixed to the command for - * temporary table creation. - * - * @return Any required postfix. - */ - public String getCreateTemporaryTablePostfix() { - return ""; - } - - /** - * Command used to drop a temporary table. - * - * @return The command used to drop a temporary table. - */ - public String getDropTemporaryTableString() { - return "drop table"; - } - - /** - * Does the dialect require that temporary table DDL statements occur in - * isolation from other statements? This would be the case if the creation - * would cause any current transaction to get committed implicitly. - *

- * JDBC defines a standard way to query for this information via the - * {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()} - * method. However, that does not distinguish between temporary table - * DDL and other forms of DDL; MySQL, for example, reports DDL causing a - * transaction commit via its driver, even though that is not the case for - * temporary table DDL. - *

- * Possible return values and their meanings:

- * - * @return see the result matrix above. - */ - public Boolean performTemporaryTableDDLInIsolation() { - return null; - } - - /** - * Do we need to drop the temporary table after use? - * - * @return True if the table should be dropped. - */ - public boolean dropTemporaryTableAfterUse() { - return true; - } - - // callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** @@ -2007,16 +1916,11 @@ public final String quote(String name) { private StandardForeignKeyExporter foreignKeyExporter = new StandardForeignKeyExporter( this ); private StandardUniqueKeyExporter uniqueKeyExporter = new StandardUniqueKeyExporter( this ); private StandardAuxiliaryDatabaseObjectExporter auxiliaryObjectExporter = new StandardAuxiliaryDatabaseObjectExporter( this ); - private TemporaryTableExporter temporaryTableExporter = new TemporaryTableExporter( this ); public Exporter getTableExporter() { return tableExporter; } - public Exporter
getTemporaryTableExporter() { - return temporaryTableExporter; - } - public Exporter getSequenceExporter() { return sequenceExporter; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 0794b26b0e..6c6904336d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -28,6 +28,7 @@ import org.hibernate.JDBCException; import org.hibernate.PessimisticLockException; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.function.AvgWithArgumentCastFunction; import org.hibernate.dialect.function.NoArgSQLFunction; @@ -42,6 +43,10 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.ReflectHelper; @@ -395,32 +400,24 @@ public JDBCException convert(SQLException sqlException, String message, String s } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create cached local temporary table if not exists"; + } - @Override - public String getCreateTemporaryTableString() { - return "create cached local temporary table if not exists"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - // actually 2 different options are specified here: - // 1) [on commit drop] - says to drop the table on transaction commit - // 2) [transactional] - says to not perform an implicit commit of any current transaction - return "on commit drop transactional"; - } - - @Override - public Boolean performTemporaryTableDDLInIsolation() { - // explicitly create the table using the same connection and transaction - return Boolean.FALSE; - } - - @Override - public boolean dropTemporaryTableAfterUse() { - return false; + @Override + public String getCreateIdTableStatementOptions() { + // actually 2 different options are specified here: + // 1) [on commit drop] - says to drop the table on transaction commit + // 2) [transactional] - says to not perform an implicit commit of any current transaction + return "on commit drop transactional"; } + }, + AfterUseAction.CLEAN, + TempTableDdlTransactionHandling.NONE + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index 693fd1591b..257ac8ca50 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -32,6 +32,7 @@ import org.hibernate.LockMode; import org.hibernate.MappingException; import org.hibernate.StaleObjectStateException; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.AvgWithArgumentCastFunction; import org.hibernate.dialect.function.NoArgSQLFunction; @@ -52,6 +53,11 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.ReflectHelper; @@ -516,73 +522,54 @@ public boolean supportsUnionAll() { return true; } - // temporary table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // Hibernate uses this information for temporary tables that it uses for its own operations - // therefore the appropriate strategy is taken with different versions of HSQLDB - - // All versions of HSQLDB support GLOBAL TEMPORARY tables where the table - // definition is shared by all users but data is private to the session - // HSQLDB 2.0 also supports session-based LOCAL TEMPORARY tables where - // the definition and data is private to the session and table declaration - // can happen in the middle of a transaction - @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + // Hibernate uses this information for temporary tables that it uses for its own operations + // therefore the appropriate strategy is taken with different versions of HSQLDB + + // All versions of HSQLDB support GLOBAL TEMPORARY tables where the table + // definition is shared by all users but data is private to the session + // HSQLDB 2.0 also supports session-based LOCAL TEMPORARY tables where + // the definition and data is private to the session and table declaration + // can happen in the middle of a transaction - @Override - public String generateTemporaryTableName(String baseTableName) { if ( hsqldbVersion < 20 ) { - return "HT_" + baseTableName; + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + return "HT_" + baseName; + } + + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } + }, + // Version 1.8 GLOBAL TEMPORARY table definitions persist beyond the end + // of the session (by default, data is cleared at commit). + AfterUseAction.CLEAN + ); } else { - // With HSQLDB 2.0, the table name is qualified with MODULE to assist the drop - // statement (in-case there is a global name beginning with HT_) - return "MODULE.HT_" + baseTableName; - } - } + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + // With HSQLDB 2.0, the table name is qualified with MODULE to assist the drop + // statement (in-case there is a global name beginning with HT_) + return "MODULE.HT_" + baseName; + } - @Override - public String getCreateTemporaryTableString() { - if ( hsqldbVersion < 20 ) { - return "create global temporary table"; + @Override + public String getCreateIdTableCommand() { + return "declare local temporary table"; + } + }, + AfterUseAction.DROP, + TempTableDdlTransactionHandling.NONE + ); } - else { - return "declare local temporary table"; - } - } - - @Override - public String getCreateTemporaryTablePostfix() { - return ""; - } - - @Override - public String getDropTemporaryTableString() { - return "drop table"; - } - - @Override - public Boolean performTemporaryTableDDLInIsolation() { - // Different behavior for GLOBAL TEMPORARY (1.8) and LOCAL TEMPORARY (2.0) - if ( hsqldbVersion < 20 ) { - return Boolean.TRUE; - } - else { - return Boolean.FALSE; - } - } - - @Override - public boolean dropTemporaryTableAfterUse() { - // Version 1.8 GLOBAL TEMPORARY table definitions persist beyond the end - // of the session (by default, data is cleared at commit).

- // - // Version 2.x LOCAL TEMPORARY table definitions do not persist beyond - // the end of the session (by default, data is cleared at commit). - return true; } // current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java index 614d7dc8c2..12bcae35a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java @@ -28,6 +28,7 @@ import java.util.Locale; import org.hibernate.MappingException; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.dialect.function.VarArgsSQLFunction; import org.hibernate.dialect.pagination.FirstLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; @@ -35,6 +36,10 @@ import org.hibernate.dialect.unique.UniqueDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.type.StandardBasicTypes; @@ -287,18 +292,22 @@ public String getCurrentTimestampSelectString() { } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create temp table"; + } - @Override - public String getCreateTemporaryTableString() { - return "create temp table"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return "with no log"; + @Override + public String getCreateIdTableStatementOptions() { + return "with no log"; + } + }, + AfterUseAction.CLEAN, + null + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java index 905d9b171a..e5db5930c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java @@ -32,6 +32,10 @@ import org.hibernate.dialect.function.VarArgsSQLFunction; import org.hibernate.dialect.pagination.FirstLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.type.StandardBasicTypes; /** @@ -268,24 +272,28 @@ public boolean useMaxForLimit() { } @Override - public boolean supportsTemporaryTables() { - return true; + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + return "session." + super.generateIdTableName( baseName ); + } + + @Override + public String getCreateIdTableCommand() { + return "declare global temporary table"; + } + + @Override + public String getCreateIdTableStatementOptions() { + return "on commit preserve rows with norecovery"; + } + }, + AfterUseAction.CLEAN + ); } - @Override - public String getCreateTemporaryTableString() { - return "declare global temporary table"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return "on commit preserve rows with norecovery"; - } - - @Override - public String generateTemporaryTableName(String baseTableName) { - return "session." + super.generateTemporaryTableName( baseTableName ); - } @Override public String getCurrentTimestampSQLFunctionName() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 2ed59b0e11..2798700906 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -30,6 +30,7 @@ import org.hibernate.JDBCException; import org.hibernate.NullPrecedence; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.StandardSQLFunction; @@ -40,6 +41,11 @@ import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; +import org.hibernate.hql.spi.id.IdTableSupport; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.type.StandardBasicTypes; @@ -314,25 +320,22 @@ public String getColumnComment(String comment) { } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create temporary table if not exists"; + } - @Override - public String getCreateTemporaryTableString() { - return "create temporary table if not exists"; - } - - @Override - public String getDropTemporaryTableString() { - return "drop temporary table"; - } - - @Override - public Boolean performTemporaryTableDDLInIsolation() { - // because we [drop *temporary* table...] we do not - // have to doAfterTransactionCompletion these in isolation. - return Boolean.FALSE; + @Override + public String getDropIdTableCommand() { + return "drop temporary table"; + } + }, + AfterUseAction.DROP, + TempTableDdlTransactionHandling.NONE + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java index c57be684dd..1484b04aa1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java @@ -49,8 +49,10 @@ 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.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.procedure.internal.StandardCallableStatementSupport; import org.hibernate.procedure.spi.CallableStatementSupport; @@ -586,33 +588,26 @@ public boolean supportsCommentOn() { @Override public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { - return new GlobalTemporaryTableBulkIdStrategy(); - } + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + final String name = super.generateIdTableName( baseName ); + return name.length() > 30 ? name.substring( 0, 30 ) : name; + } - @Override - public boolean supportsTemporaryTables() { - return true; - } + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } - @Override - public String generateTemporaryTableName(String baseTableName) { - final String name = super.generateTemporaryTableName( baseTableName ); - return name.length() > 30 ? name.substring( 0, 30 ) : name; - } - - @Override - public String getCreateTemporaryTableString() { - return "create global temporary table"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return "on commit delete rows"; - } - - @Override - public boolean dropTemporaryTableAfterUse() { - return false; + @Override + public String getCreateIdTableStatementOptions() { + return "on commit delete rows"; + } + }, + AfterUseAction.CLEAN + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java index 51c83a1246..8a8218a897 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java @@ -37,8 +37,10 @@ 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.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.type.StandardBasicTypes; @@ -355,33 +357,26 @@ public boolean supportsCommentOn() { @Override public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { - return new GlobalTemporaryTableBulkIdStrategy(); - } + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + final String name = super.generateIdTableName( baseName ); + return name.length() > 30 ? name.substring( 0, 30 ) : name; + } - @Override - public boolean supportsTemporaryTables() { - return true; - } + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } - @Override - public String generateTemporaryTableName(String baseTableName) { - final String name = super.generateTemporaryTableName( baseTableName ); - return name.length() > 30 ? name.substring( 1, 30 ) : name; - } - - @Override - public String getCreateTemporaryTableString() { - return "create global temporary table"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return "on commit delete rows"; - } - - @Override - public boolean dropTemporaryTableAfterUse() { - return false; + @Override + public String getCreateIdTableStatementOptions() { + return "on commit delete rows"; + } + }, + AfterUseAction.CLEAN + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index 8bba7e8d40..f4c8e9c43a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -31,6 +31,7 @@ import org.hibernate.JDBCException; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; +import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.PositionSubstringFunction; @@ -45,6 +46,10 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.id.SequenceGenerator; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.procedure.internal.PostgresCallableStatementSupport; @@ -366,18 +371,22 @@ public boolean supportsCommentOn() { } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create temporary table"; + } - @Override - public String getCreateTemporaryTableString() { - return "create temporary table"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return "on commit drop"; + @Override + public String getCreateIdTableStatementOptions() { + return "on commit drop"; + } + }, + AfterUseAction.CLEAN, + null + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SAPDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SAPDBDialect.java index 2c6448498b..faa67d3a60 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SAPDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SAPDBDialect.java @@ -30,6 +30,11 @@ import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.internal.util.StringHelper; import org.hibernate.sql.CaseFragment; import org.hibernate.sql.DecodeCaseFragment; @@ -220,18 +225,21 @@ public CaseFragment createCaseFragment() { } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new LocalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + return "temp." + super.generateIdTableName( baseName ); + } - @Override - public String getCreateTemporaryTablePostfix() { - return "ignore rollback"; + @Override + public String getCreateIdTableStatementOptions() { + return "ignore rollback"; + } + }, + AfterUseAction.DROP, + null + ); } - - @Override - public String generateTemporaryTableName(String baseTableName) { - return "temp." + super.generateTemporaryTableName( baseTableName ); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java index e713cb8b58..54918fdcfc 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java @@ -108,11 +108,6 @@ public String getIdentityInsertString() { return "null"; } - @Override - public String getDropTemporaryTableString() { - return "drop temporary table"; - } - @Override public boolean supportsExpectedLobUsagePattern() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java index 942057aa64..f9f4b80867 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java @@ -28,6 +28,11 @@ import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.hql.spi.id.IdTableSupport; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.type.StandardBasicTypes; /** @@ -36,7 +41,7 @@ * * @author Jay Nance */ -public class TeradataDialect extends Dialect { +public class TeradataDialect extends Dialect implements IdTableSupport { private static final int PARAM_LIST_SIZE_LIMIT = 1024; @@ -133,24 +138,29 @@ public String getAddColumnString() { return "Add Column"; } - public boolean supportsTemporaryTables() { - return true; + @Override + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new GlobalTemporaryTableBulkIdStrategy( this, AfterUseAction.CLEAN ); } - public String getCreateTemporaryTableString() { + @Override + public String generateIdTableName(String baseName) { + return IdTableSupportStandardImpl.INSTANCE.generateIdTableName( baseName ); + } + + @Override + public String getCreateIdTableCommand() { return "create global temporary table"; } - public String getCreateTemporaryTablePostfix() { + @Override + public String getCreateIdTableStatementOptions() { return " on commit preserve rows"; } - public Boolean performTemporaryTableDDLInIsolation() { - return Boolean.TRUE; - } - - public boolean dropTemporaryTableAfterUse() { - return false; + @Override + public String getDropIdTableCommand() { + return "drop table"; } /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java index 44f1ae4ea2..808305385f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java @@ -39,6 +39,11 @@ import org.hibernate.dialect.lock.UpdateLockingStrategy; import org.hibernate.dialect.pagination.FirstLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.AfterUseAction; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.persister.entity.Lockable; import org.hibernate.sql.JoinFragment; import org.hibernate.sql.OracleJoinFragment; @@ -222,24 +227,27 @@ public boolean isCurrentTimestampSelectStringCallable() { } @Override - public boolean supportsTemporaryTables() { - return true; - } + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return new GlobalTemporaryTableBulkIdStrategy( + new IdTableSupportStandardImpl() { + @Override + public String generateIdTableName(String baseName) { + final String name = super.generateIdTableName( baseName ); + return name.length() > 30 ? name.substring( 1, 30 ) : name; + } - @Override - public String generateTemporaryTableName(String baseTableName) { - final String name = super.generateTemporaryTableName( baseTableName ); - return name.length() > 30 ? name.substring( 1, 30 ) : name; - } + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } - @Override - public String getCreateTemporaryTableString() { - return "create global temporary table"; - } - - @Override - public String getCreateTemporaryTablePostfix() { - return "on commit delete rows"; + @Override + public String getCreateIdTableStatementOptions() { + return "on commit delete rows"; + } + }, + AfterUseAction.CLEAN + ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableDeleteExecutor.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableDeleteExecutor.java index 9fb74e5e66..a895992743 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableDeleteExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableDeleteExecutor.java @@ -29,7 +29,7 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.event.spi.EventSource; import org.hibernate.hql.internal.ast.HqlSqlWalker; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; /** * Implementation of MultiTableDeleteExecutor. diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableUpdateExecutor.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableUpdateExecutor.java index b78afe8f3f..47991563d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableUpdateExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/MultiTableUpdateExecutor.java @@ -30,7 +30,7 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.event.spi.EventSource; import org.hibernate.hql.internal.ast.HqlSqlWalker; -import org.hibernate.hql.spi.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; /** * Implementation of MultiTableUpdateExecutor. diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/GlobalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/GlobalTemporaryTableBulkIdStrategy.java deleted file mode 100644 index 04f2390384..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/GlobalTemporaryTableBulkIdStrategy.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 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

idTableDefinitions = new ArrayList
(); - - 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(); - } - 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
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 ); - } - }; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/PersistentTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/PersistentTableBulkIdStrategy.java deleted file mode 100644 index 29f24cd4e9..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/PersistentTableBulkIdStrategy.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2012, 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.sql.SQLException; -import java.sql.Types; -import java.util.ArrayList; -import java.util.List; - -import org.hibernate.HibernateException; -import org.hibernate.JDBCException; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; -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.internal.AbstractSessionImpl; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Table; -import org.hibernate.persister.entity.Queryable; -import org.hibernate.sql.SelectValues; -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 { - private static final CoreMessageLogger log = Logger.getMessageLogger( - CoreMessageLogger.class, - PersistentTableBulkIdStrategy.class.getName() - ); - - public static final String SHORT_NAME = "persistent"; - - public static final String CLEAN_UP_ID_TABLES = "hibernate.hql.bulk_id_strategy.persistent.clean_up"; - public static final String SCHEMA = "hibernate.hql.bulk_id_strategy.persistent.schema"; - public static final String CATALOG = "hibernate.hql.bulk_id_strategy.persistent.catalog"; - - private String catalog; - private String schema; - private boolean cleanUpTables; - private List 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, - JdbcConnectionAccess connectionAccess, - MetadataImplementor metadata) { - final ConfigurationService configService = metadata.getMetadataBuildingOptions() - .getServiceRegistry() - .getService( ConfigurationService.class ); - this.catalog = configService.getSetting( - CATALOG, - StandardConverters.STRING, - configService.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING ) - ); - this.schema = configService.getSetting( - SCHEMA, - StandardConverters.STRING, - configService.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING ) - ); - this.cleanUpTables = configService.getSetting( - CLEAN_UP_ID_TABLES, - StandardConverters.BOOLEAN, - false - ); - - final List
idTableDefinitions = new ArrayList
(); - - 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(); - } - 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, - catalog, - schema, - true - ); - } - - protected void exportTableDefinitions( - List
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, catalog, schema ) { - @Override - protected void addAnyExtraIdSelectValues(SelectValues selectClause) { - selectClause.addParameter( Types.CHAR, 36 ); - } - - @Override - protected String generateIdSubselect(Queryable persister) { - return super.generateIdSubselect( persister ) + " where hib_sess_id=?"; - } - - @Override - protected int handlePrependedParametersOnIdSelection(PreparedStatement ps, SessionImplementor session, int pos) throws SQLException { - bindSessionIdentifier( ps, session, pos ); - return 1; - } - - @Override - protected void handleAddedParametersOnUpdate(PreparedStatement ps, SessionImplementor session, int position) throws SQLException { - bindSessionIdentifier( ps, session, position ); - } - - @Override - protected void releaseFromUse(Queryable persister, SessionImplementor session) { - // clean up our id-table rows - cleanUpRows( determineIdTableName( persister ), session ); - } - }; - } - - private void bindSessionIdentifier(PreparedStatement ps, SessionImplementor session, int position) throws SQLException { - if ( ! AbstractSessionImpl.class.isInstance( session ) ) { - throw new HibernateException( "Only available on SessionImpl instances" ); - } - UUIDCharType.INSTANCE.set( ps, ( (AbstractSessionImpl) session ).getSessionIdentifier(), position, session ); - } - - private void cleanUpRows(String tableName, SessionImplementor session) { - final String sql = "delete from " + tableName + " where hib_sess_id=?"; - try { - PreparedStatement ps = null; - try { - ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false ); - bindSessionIdentifier( ps, session, 1 ); - session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps ); - } - finally { - if ( ps != null ) { - try { - session.getTransactionCoordinator().getJdbcCoordinator().release( ps ); - } - catch( Throwable ignore ) { - // ignore - } - } - } - } - catch (SQLException e) { - throw convert( session.getFactory(), e, "Unable to clean up id table [" + tableName + "]", sql ); - } - } - - protected JDBCException convert(SessionFactoryImplementor factory, SQLException e, String message, String sql) { - throw factory.getSQLExceptionHelper().convert( e, message, sql ); - } - - @Override - public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { - return new TableBasedDeleteHandlerImpl( factory, walker, catalog, schema ) { - @Override - protected void addAnyExtraIdSelectValues(SelectValues selectClause) { - selectClause.addParameter( Types.CHAR, 36 ); - } - - @Override - protected String generateIdSubselect(Queryable persister) { - return super.generateIdSubselect( persister ) + " where hib_sess_id=?"; - } - - @Override - protected int handlePrependedParametersOnIdSelection(PreparedStatement ps, SessionImplementor session, int pos) throws SQLException { - bindSessionIdentifier( ps, session, pos ); - return 1; - } - - @Override - protected void handleAddedParametersOnDelete(PreparedStatement ps, SessionImplementor session) throws SQLException { - bindSessionIdentifier( ps, session, 1 ); - } - - @Override - protected void releaseFromUse(Queryable persister, SessionImplementor session) { - // clean up our id-table rows - cleanUpRows( determineIdTableName( persister ), session ); - } - }; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/TemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/TemporaryTableBulkIdStrategy.java deleted file mode 100644 index 758b034646..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/TemporaryTableBulkIdStrategy.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2012, 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 org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; -import org.hibernate.engine.jdbc.spi.JdbcServices; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.hql.internal.ast.HqlSqlWalker; -import org.hibernate.internal.log.DeprecationLogger; - -/** - * @author Steve Ebersole - * - * @deprecated Use the more specific {@link org.hibernate.hql.spi.LocalTemporaryTableBulkIdStrategy} instead. - */ -@Deprecated -public class TemporaryTableBulkIdStrategy extends LocalTemporaryTableBulkIdStrategy { - public static final TemporaryTableBulkIdStrategy INSTANCE = new TemporaryTableBulkIdStrategy(); - - public static final String SHORT_NAME = "temporary"; - - @Override - public void prepare(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata) { - DeprecationLogger.DEPRECATION_LOGGER.logDeprecationOfTemporaryTableBulkIdStrategy(); - super.prepare( jdbcServices, connectionAccess, metadata ); - } - - @Override - public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) { - super.release( jdbcServices, connectionAccess ); - } - - @Override - public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { - return super.buildUpdateHandler( factory, walker ); - } - - @Override - public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { - return super.buildDeleteHandler( factory, walker ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java new file mode 100644 index 0000000000..ad06120d7c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java @@ -0,0 +1,213 @@ +/* + * 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.id; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.hibernate.QueryException; +import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.spi.MetadataBuildingOptions; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Table; +import org.hibernate.persister.entity.Queryable; + +/** + * Convenience base class for MultiTableBulkIdStrategy implementations. + * + * @author Steve Ebersole + */ +public abstract class AbstractMultiTableBulkIdStrategyImpl + implements MultiTableBulkIdStrategy { + + private final IdTableSupport idTableSupport; + private Map idTableInfoMap = new HashMap(); + + public AbstractMultiTableBulkIdStrategyImpl(IdTableSupport idTableSupport) { + this.idTableSupport = idTableSupport; + } + + public IdTableSupport getIdTableSupport() { + return idTableSupport; + } + + @Override + public final void prepare( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess, + MetadataImplementor metadata, + SessionFactoryOptions sessionFactoryOptions) { + // build/get Table representation of the bulk-id tables - subclasses need hooks + // for each: + // handle DDL + // build insert-select + // build id-subselect + + final CT context = buildPreparationContext(); + + initialize( metadata.getMetadataBuildingOptions(), sessionFactoryOptions ); + + final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); + + for ( PersistentClass entityBinding : metadata.getEntityBindings() ) { + if ( !IdTableHelper.INSTANCE.needsIdTable( entityBinding ) ) { + continue; + } + + final String idTableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( + determineIdTableName( jdbcEnvironment, entityBinding ), + jdbcEnvironment.getDialect() + ); + final Table idTable = new Table(); + idTable.setName( idTableName ); + idTable.setComment( "Used to hold id values for the " + entityBinding.getEntityName() + " entity" ); + + Iterator itr = entityBinding.getTable().getPrimaryKey().getColumnIterator(); + while( itr.hasNext() ) { + Column column = (Column) itr.next(); + idTable.addColumn( column.clone() ); + } + augmentIdTableDefinition( idTable ); + + final TT idTableInfo = buildIdTableInfo( entityBinding, idTable, jdbcServices, metadata, context ); + idTableInfoMap.put( entityBinding.getEntityName(), idTableInfo ); + } + + finishPreparation( jdbcServices, connectionAccess, metadata, context ); + } + + protected CT buildPreparationContext() { + return null; + } + + + /** + * Configure ourselves. By default, nothing to do; here totally for subclass hook-in + * + * @param buildingOptions Access to user-defined Metadata building options + * @param sessionFactoryOptions + */ + protected void initialize(MetadataBuildingOptions buildingOptions, SessionFactoryOptions sessionFactoryOptions) { + // by default nothing to do + } + + protected QualifiedTableName determineIdTableName(JdbcEnvironment jdbcEnvironment, PersistentClass entityBinding) { + final String entityPrimaryTableName = entityBinding.getTable().getName(); + final String idTableName = getIdTableSupport().generateIdTableName( entityPrimaryTableName ); + + // by default no explicit catalog/schema + return new QualifiedTableName( + null, + null, + jdbcEnvironment.getIdentifierHelper().toIdentifier( idTableName ) + ); + + } + + protected void augmentIdTableDefinition(Table idTable) { + // by default nothing to do + } + + protected abstract TT buildIdTableInfo( + PersistentClass entityBinding, + Table idTable, + JdbcServices jdbcServices, + MetadataImplementor metadata, + CT context); + + + protected String buildIdTableCreateStatement(Table idTable, JdbcServices jdbcServices, MetadataImplementor metadata) { + final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); + final Dialect dialect = jdbcEnvironment.getDialect(); + + StringBuilder buffer = new StringBuilder( getIdTableSupport().getCreateIdTableCommand() ) + .append( ' ' ) + .append( jdbcEnvironment.getQualifiedObjectNameFormatter().format( idTable.getQualifiedTableName(), dialect ) ) + .append( " (" ); + + Iterator itr = idTable.getColumnIterator(); + while ( itr.hasNext() ) { + final Column column = (Column) itr.next(); + buffer.append( column.getQuotedName( dialect ) ).append( ' ' ); + buffer.append( column.getSqlType( dialect, metadata ) ); + if ( column.isNullable() ) { + buffer.append( dialect.getNullColumnString() ); + } + else { + buffer.append( " not null" ); + } + if ( itr.hasNext() ) { + buffer.append( ", " ); + } + } + + buffer.append( ") " ); + if ( getIdTableSupport().getCreateIdTableStatementOptions() != null ) { + buffer.append( getIdTableSupport().getCreateIdTableStatementOptions() ); + } + + return buffer.toString(); + } + + protected String buildIdTableDropStatement(Table idTable, JdbcServices jdbcServices) { + final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); + final Dialect dialect = jdbcEnvironment.getDialect(); + + return getIdTableSupport().getDropIdTableCommand() + " " + + jdbcEnvironment.getQualifiedObjectNameFormatter().format( idTable.getQualifiedTableName(), dialect ); + } + + protected void finishPreparation( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess, + MetadataImplementor metadata, + CT context) { + } + + protected TT getIdTableInfo(Queryable targetedPersister) { + return getIdTableInfo( targetedPersister.getEntityName() ); + } + + protected TT getIdTableInfo(String entityName) { + TT tableInfo = idTableInfoMap.get( entityName ); + if ( tableInfo == null ) { + throw new QueryException( "Entity does not have an id table for multi-table handling : " + entityName ); + } + return tableInfo; + } + + public static interface PreparationContext { + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/AbstractTableBasedBulkIdHandler.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/hql/spi/AbstractTableBasedBulkIdHandler.java rename to hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java index 4e6e9ff936..c28da9ceaa 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/AbstractTableBasedBulkIdHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.hql.spi; +package org.hibernate.hql.spi.id; import java.sql.SQLException; import java.util.Collections; @@ -34,7 +34,6 @@ import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.internal.ast.SqlGenerator; import org.hibernate.internal.util.StringHelper; -import org.hibernate.mapping.Table; import org.hibernate.param.ParameterSpecification; import org.hibernate.persister.entity.Queryable; import org.hibernate.sql.InsertSelect; @@ -45,24 +44,27 @@ import antlr.collections.AST; /** + * Convenience base class for {@link MultiTableBulkIdStrategy.UpdateHandler} + * and {@link MultiTableBulkIdStrategy.DeleteHandler} implementations through + * {@link TableBasedUpdateHandlerImpl} and {@link TableBasedDeleteHandlerImpl} respectively. + *

+ * Mainly supports common activities like:

    + *
  • processing the original {@code WHERE} clause (if one) - {@link #processWhereClause}
  • + *
  • generating the proper {@code SELECT} clause for the id-table insert - {@link #generateIdInsertSelect}
  • + *
  • generating the sub-select from the id-table - {@link #generateIdSubselect}
  • + *
+ * * @author Steve Ebersole */ public abstract class AbstractTableBasedBulkIdHandler { private final SessionFactoryImplementor sessionFactory; private final HqlSqlWalker walker; - private final String catalog; - private final String schema; - public AbstractTableBasedBulkIdHandler( SessionFactoryImplementor sessionFactory, - HqlSqlWalker walker, - String catalog, - String schema) { + HqlSqlWalker walker) { this.sessionFactory = sessionFactory; this.walker = walker; - this.catalog = catalog; - this.schema = schema; } protected SessionFactoryImplementor factory() { @@ -73,6 +75,8 @@ protected HqlSqlWalker walker() { return walker; } + public abstract Queryable getTargetedQueryable(); + protected JDBCException convert(SQLException e, String message, String sql) { throw factory().getSQLExceptionHelper().convert( e, message, sql ); } @@ -101,11 +105,18 @@ public List getIdSelectParameterSpecifications() { } } + /** + * Interprets the {@code WHERE} clause from the user-defined update/delete query + * + * @param whereClause The user-defined {@code WHERE} clause + * + * @return The bulk-id-ready {@code WHERE} clause representation + */ @SuppressWarnings("unchecked") protected ProcessedWhereClause processWhereClause(AST whereClause) { if ( whereClause.getNumberOfChildren() != 0 ) { // If a where clause was specified in the update/delete query, use it to limit the - // returned ids here... + // ids that will be returned and inserted into the id table... try { SqlGenerator sqlGenerator = new SqlGenerator( sessionFactory ); sqlGenerator.whereClause( whereClause ); @@ -123,16 +134,33 @@ protected ProcessedWhereClause processWhereClause(AST whereClause) { } } - protected String generateIdInsertSelect(Queryable persister, String tableAlias, ProcessedWhereClause whereClause) { + /** + * Generate the {@code INSERT}-{@code SELECT} statement for holding matching ids. This is the + * {@code INSERT} used to populate the bulk-id table with ids matching the restrictions defined in the + * original {@code WHERE} clause + * + * @param tableAlias The table alias to use for the entity + * @param whereClause The processed representation for the user-defined {@code WHERE} clause. + * + * @return The {@code INSERT}-{@code SELECT} for populating the bulk-id table. + */ + protected String generateIdInsertSelect( + String tableAlias, + IdTableInfo idTableInfo, + ProcessedWhereClause whereClause) { + Select select = new Select( sessionFactory.getDialect() ); - SelectValues selectClause = new SelectValues( sessionFactory.getDialect() ) - .addColumns( tableAlias, persister.getIdentifierColumnNames(), persister.getIdentifierColumnNames() ); + SelectValues selectClause = new SelectValues( sessionFactory.getDialect() ).addColumns( + tableAlias, + getTargetedQueryable().getIdentifierColumnNames(), + getTargetedQueryable().getIdentifierColumnNames() + ); addAnyExtraIdSelectValues( selectClause ); select.setSelectClause( selectClause.render() ); - String rootTableName = persister.getTableName(); - String fromJoinFragment = persister.fromJoinFragment( tableAlias, true, false ); - String whereJoinFragment = persister.whereJoinFragment( tableAlias, true, false ); + String rootTableName = getTargetedQueryable().getTableName(); + String fromJoinFragment = getTargetedQueryable().fromJoinFragment( tableAlias, true, false ); + String whereJoinFragment = getTargetedQueryable().whereJoinFragment( tableAlias, true, false ); select.setFromClause( rootTableName + ' ' + tableAlias + fromJoinFragment ); @@ -155,24 +183,26 @@ protected String generateIdInsertSelect(Queryable persister, String tableAlias, InsertSelect insert = new InsertSelect( sessionFactory.getDialect() ); if ( sessionFactory.getSettings().isCommentsEnabled() ) { - insert.setComment( "insert-select for " + persister.getEntityName() + " ids" ); + insert.setComment( "insert-select for " + getTargetedQueryable().getEntityName() + " ids" ); } - insert.setTableName( determineIdTableName( persister ) ); + insert.setTableName( idTableInfo.getQualifiedIdTableName() ); insert.setSelect( select ); return insert.toStatementString(); } + /** + * Used from {@link #generateIdInsertSelect} to allow subclasses to define any extra + * values to be selected (and therefore stored into the bulk-id table). Used to store + * session identifier, e.g. + * + * @param selectClause The SelectValues that defines the select clause of the insert statement. + */ protected void addAnyExtraIdSelectValues(SelectValues selectClause) { } - protected String determineIdTableName(Queryable persister) { - // todo : use the identifier/name qualifier service once we pull that over to master - return Table.qualify( catalog, schema, persister.getTemporaryIdTableName() ); - } - - protected String generateIdSubselect(Queryable persister) { + protected String generateIdSubselect(Queryable persister, IdTableInfo idTableInfo) { return "select " + StringHelper.join( ", ", persister.getIdentifierColumnNames() ) + - " from " + determineIdTableName( persister ); + " from " + idTableInfo.getQualifiedIdTableName(); } protected void prepareForUse(Queryable persister, SessionImplementor session) { diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/MultiTableBulkIdHelper.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java similarity index 67% rename from hibernate-core/src/main/java/org/hibernate/hql/spi/MultiTableBulkIdHelper.java rename to hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java index e8fd8fdb19..3f7f3d7e5d 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/MultiTableBulkIdHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.hql.spi; +package org.hibernate.hql.spi.id; import java.sql.Connection; import java.sql.SQLException; @@ -29,15 +29,12 @@ 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; @@ -45,15 +42,15 @@ /** * @author Steve Ebersole */ -public class MultiTableBulkIdHelper { - private static final Logger log = Logger.getLogger( MultiTableBulkIdHelper.class ); +public class IdTableHelper { + private static final Logger log = Logger.getLogger( IdTableHelper.class ); /** * Singleton access */ - public static final MultiTableBulkIdHelper INSTANCE = new MultiTableBulkIdHelper(); + public static final IdTableHelper INSTANCE = new IdTableHelper(); - private MultiTableBulkIdHelper() { + private IdTableHelper() { } public boolean needsIdTable(PersistentClass entityBinding) { @@ -77,43 +74,10 @@ public boolean needsIdTable(PersistentClass entityBinding) { 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
idTableDefinitions, + public void executeIdTableCreationStatements( + List creationStatements, JdbcServices jdbcServices, - JdbcConnectionAccess connectionAccess, - MetadataImplementor metadata) { + JdbcConnectionAccess connectionAccess) { try { Connection connection; try { @@ -128,15 +92,14 @@ protected void exportTableDefinitions( try { // TODO: session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().createStatement(); Statement statement = connection.createStatement(); - for ( Table idTableDefinition : idTableDefinitions ) { + for ( String creationStatement : creationStatements ) { try { - final String sql = idTableDefinition.sqlCreateString( jdbcServices.getDialect(), metadata, null, null ); - jdbcServices.getSqlStatementLogger().logStatement( sql ); + jdbcServices.getSqlStatementLogger().logStatement( creationStatement ); // TODO: ResultSetExtractor - statement.execute( sql ); + statement.execute( creationStatement ); } catch (SQLException e) { - log.debugf( "Error attempting to export id-table [%s] : %s", idTableDefinition.getName(), e.getMessage() ); + log.debugf( "Error attempting to export id-table [%s] : %s", creationStatement, e.getMessage() ); } } @@ -160,11 +123,11 @@ protected void exportTableDefinitions( } } - public void cleanupTableDefinitions( + public void executeIdTableDropStatements( + String[] dropStatements, JdbcServices jdbcServices, - JdbcConnectionAccess connectionAccess, - List tableCleanUpDdl) { - if ( tableCleanUpDdl == null ) { + JdbcConnectionAccess connectionAccess) { + if ( dropStatements == null ) { return; } @@ -175,10 +138,10 @@ public void cleanupTableDefinitions( // TODO: session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().createStatement(); Statement statement = connection.createStatement(); - for ( String cleanupDdl : tableCleanUpDdl ) { + for ( String dropStatement : dropStatements ) { try { - jdbcServices.getSqlStatementLogger().logStatement( cleanupDdl ); - statement.execute( cleanupDdl ); + jdbcServices.getSqlStatementLogger().logStatement( dropStatement ); + statement.execute( dropStatement ); } catch (SQLException e) { log.debugf( "Error attempting to cleanup id-table : [%s]", e.getMessage() ); @@ -204,4 +167,5 @@ public void cleanupTableDefinitions( log.error( "Unable obtain JDBC Connection", e ); } } + } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableInfo.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableInfo.java new file mode 100644 index 0000000000..05b0ec7ada --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableInfo.java @@ -0,0 +1,31 @@ +/* + * 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.id; + +/** + * @author Steve Ebersole + */ +public interface IdTableInfo { + String getQualifiedIdTableName(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableSupport.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableSupport.java new file mode 100644 index 0000000000..4ebd8bc3b8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableSupport.java @@ -0,0 +1,36 @@ +/* + * 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.id; + +import org.hibernate.hql.spi.id.local.AfterUseAction; + +/** + * @author Steve Ebersole + */ +public interface IdTableSupport { + public String generateIdTableName(String baseName); + public String getCreateIdTableCommand(); + public String getCreateIdTableStatementOptions(); + public String getDropIdTableCommand(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableSupportStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableSupportStandardImpl.java new file mode 100644 index 0000000000..de1ad2f197 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableSupportStandardImpl.java @@ -0,0 +1,54 @@ +/* + * 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.id; + +/** +* @author Steve Ebersole +*/ +public class IdTableSupportStandardImpl implements IdTableSupport { + /** + * Singleton access + */ + public static final IdTableSupportStandardImpl INSTANCE = new IdTableSupportStandardImpl(); + + @Override + public String generateIdTableName(String baseName) { + return "HT_" + baseName; + } + + @Override + public String getCreateIdTableCommand() { + return "create table"; + } + + @Override + public String getCreateIdTableStatementOptions() { + return null; + } + + @Override + public String getDropIdTableCommand() { + return "drop table"; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/MultiTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java similarity index 91% rename from hibernate-core/src/main/java/org/hibernate/hql/spi/MultiTableBulkIdStrategy.java rename to hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java index 78e9bc9974..c074184065 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/MultiTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java @@ -21,9 +21,10 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.hql.spi; +package org.hibernate.hql.spi.id; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.QueryParameters; @@ -43,12 +44,16 @@ public interface MultiTableBulkIdStrategy { *
  • Adding tables to the passed Mappings, to be picked by by "schema management tools"
  • *
  • Manually creating the tables immediately through the passed JDBC Connection access
  • * - * - * @param jdbcServices The JdbcService object + * @param jdbcServices The JdbcService object * @param connectionAccess Access to the JDBC Connection * @param metadata Access to the O/RM mapping information + * @param sessionFactoryOptions */ - public void prepare(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata); + public void prepare( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess, + MetadataImplementor metadata, + SessionFactoryOptions sessionFactoryOptions); /** * Release the strategy. Called as the SessionFactory is being shut down. diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/TableBasedDeleteHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java similarity index 95% rename from hibernate-core/src/main/java/org/hibernate/hql/spi/TableBasedDeleteHandlerImpl.java rename to hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java index 8e890fb492..a0c12ed817 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/TableBasedDeleteHandlerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.hql.spi; +package org.hibernate.hql.spi.id; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -58,16 +58,11 @@ public class TableBasedDeleteHandlerImpl private final List idSelectParameterSpecifications; private final List deletes; - public TableBasedDeleteHandlerImpl(SessionFactoryImplementor factory, HqlSqlWalker walker) { - this( factory, walker, null, null ); - } - public TableBasedDeleteHandlerImpl( SessionFactoryImplementor factory, HqlSqlWalker walker, - String catalog, - String schema) { - super( factory, walker, catalog, schema ); + IdTableInfo idTableInfo) { + super( factory, walker ); DeleteStatement deleteStatement = ( DeleteStatement ) walker.getAST(); FromElement fromElement = deleteStatement.getFromClause().getFromElement(); @@ -77,10 +72,10 @@ public TableBasedDeleteHandlerImpl( final ProcessedWhereClause processedWhereClause = processWhereClause( deleteStatement.getWhereClause() ); this.idSelectParameterSpecifications = processedWhereClause.getIdSelectParameterSpecifications(); - this.idInsertSelect = generateIdInsertSelect( targetedPersister, bulkTargetAlias, processedWhereClause ); + this.idInsertSelect = generateIdInsertSelect( bulkTargetAlias, idTableInfo, processedWhereClause ); log.tracev( "Generated ID-INSERT-SELECT SQL (multi-table delete) : {0}", idInsertSelect ); - final String idSubselect = generateIdSubselect( targetedPersister ); + final String idSubselect = generateIdSubselect( targetedPersister, idTableInfo ); deletes = new ArrayList(); // If many-to-many, delete the FK row in the collection table. diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/TableBasedUpdateHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedUpdateHandlerImpl.java similarity index 91% rename from hibernate-core/src/main/java/org/hibernate/hql/spi/TableBasedUpdateHandlerImpl.java rename to hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedUpdateHandlerImpl.java index cc34035020..6f858d27c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/TableBasedUpdateHandlerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedUpdateHandlerImpl.java @@ -21,11 +21,12 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.hql.spi; +package org.hibernate.hql.spi.id; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.hibernate.engine.spi.QueryParameters; @@ -60,31 +61,27 @@ public class TableBasedUpdateHandlerImpl private final ParameterSpecification[][] assignmentParameterSpecifications; @SuppressWarnings("unchecked") - public TableBasedUpdateHandlerImpl(SessionFactoryImplementor factory, HqlSqlWalker walker) { - this( factory, walker, null, null ); - } - public TableBasedUpdateHandlerImpl( SessionFactoryImplementor factory, HqlSqlWalker walker, - String catalog, - String schema) { - super( factory, walker, catalog, schema ); + IdTableInfo idTableInfo) { + super( factory, walker ); UpdateStatement updateStatement = ( UpdateStatement ) walker.getAST(); FromElement fromElement = updateStatement.getFromClause().getFromElement(); this.targetedPersister = fromElement.getQueryable(); + final String bulkTargetAlias = fromElement.getTableAlias(); final ProcessedWhereClause processedWhereClause = processWhereClause( updateStatement.getWhereClause() ); this.idSelectParameterSpecifications = processedWhereClause.getIdSelectParameterSpecifications(); - this.idInsertSelect = generateIdInsertSelect( targetedPersister, bulkTargetAlias, processedWhereClause ); + this.idInsertSelect = generateIdInsertSelect( bulkTargetAlias, idTableInfo, processedWhereClause ); log.tracev( "Generated ID-INSERT-SELECT SQL (multi-table update) : {0}", idInsertSelect ); String[] tableNames = targetedPersister.getConstraintOrderedTableNameClosure(); String[][] columnNames = targetedPersister.getContraintOrderedTableKeyColumnClosure(); - String idSubselect = generateIdSubselect( targetedPersister ); + String idSubselect = generateIdSubselect( targetedPersister, idTableInfo ); updates = new String[tableNames.length]; assignmentParameterSpecifications = new ParameterSpecification[tableNames.length][]; @@ -103,9 +100,7 @@ public TableBasedUpdateHandlerImpl( affected = true; update.appendAssignmentFragment( assignmentSpecification.getSqlAssignmentFragment() ); if ( assignmentSpecification.getParameters() != null ) { - for ( int paramIndex = 0; paramIndex < assignmentSpecification.getParameters().length; paramIndex++ ) { - parameterList.add( assignmentSpecification.getParameters()[paramIndex] ); - } + Collections.addAll( parameterList, assignmentSpecification.getParameters() ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java new file mode 100644 index 0000000000..c11f8e2ef1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java @@ -0,0 +1,225 @@ +/* + * 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.id.global; + +import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.spi.MetadataBuildingOptions; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; +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.hql.internal.ast.tree.DeleteStatement; +import org.hibernate.hql.internal.ast.tree.FromElement; +import org.hibernate.hql.internal.ast.tree.UpdateStatement; +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl; +import org.hibernate.hql.spi.id.IdTableHelper; +import org.hibernate.hql.spi.id.IdTableInfo; +import org.hibernate.hql.spi.id.IdTableSupport; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.TableBasedDeleteHandlerImpl; +import org.hibernate.hql.spi.id.TableBasedUpdateHandlerImpl; +import org.hibernate.hql.spi.id.local.AfterUseAction; +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 + extends AbstractMultiTableBulkIdStrategyImpl + implements MultiTableBulkIdStrategy { + public static final String DROP_ID_TABLES = "hibernate.hql.bulk_id_strategy.global_temporary.drop_tables"; + + public static final String SHORT_NAME = "global_temporary"; + + private final AfterUseAction afterUseAction; + + private boolean dropIdTables; + private String[] dropTableStatements; + + public GlobalTemporaryTableBulkIdStrategy() { + this( AfterUseAction.CLEAN ); + } + + public GlobalTemporaryTableBulkIdStrategy(AfterUseAction afterUseAction) { + this( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create global temporary table"; + } + + @Override + public String getDropIdTableCommand() { + return super.getDropIdTableCommand(); + } + }, + afterUseAction + ); + } + + public GlobalTemporaryTableBulkIdStrategy(IdTableSupport idTableSupport, AfterUseAction afterUseAction) { + super( idTableSupport ); + this.afterUseAction = afterUseAction; + if ( afterUseAction == AfterUseAction.DROP ) { + throw new IllegalArgumentException( "DROP not supported as a after-use action for global temp table strategy" ); + } + } + + @Override + protected PreparationContextImpl buildPreparationContext() { + return new PreparationContextImpl(); + } + + @Override + protected void initialize(MetadataBuildingOptions buildingOptions, SessionFactoryOptions sessionFactoryOptions) { + final StandardServiceRegistry serviceRegistry = buildingOptions.getServiceRegistry(); + final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); + this.dropIdTables = configService.getSetting( + DROP_ID_TABLES, + StandardConverters.BOOLEAN, + false + ); + } + + @Override + protected IdTableInfoImpl buildIdTableInfo( + PersistentClass entityBinding, + Table idTable, + JdbcServices jdbcServices, + MetadataImplementor metadata, + PreparationContextImpl context) { + context.creationStatements.add( buildIdTableCreateStatement( idTable, jdbcServices, metadata ) ); + if ( dropIdTables ) { + context.dropStatements.add( buildIdTableDropStatement( idTable, jdbcServices ) ); + } + + final String renderedName = jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( + idTable.getQualifiedTableName(), + jdbcServices.getJdbcEnvironment().getDialect() + ); + + return new IdTableInfoImpl( renderedName ); + } + + @Override + protected void finishPreparation( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess, + MetadataImplementor metadata, + PreparationContextImpl context) { + IdTableHelper.INSTANCE.executeIdTableCreationStatements( + context.creationStatements, + jdbcServices, + connectionAccess + ); + + this.dropTableStatements = dropIdTables + ? context.dropStatements.toArray( new String[ context.dropStatements.size() ] ) + : null; + } + + @Override + public void release( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess) { + if ( ! dropIdTables ) { + return; + } + + IdTableHelper.INSTANCE.executeIdTableDropStatements( dropTableStatements, jdbcServices, connectionAccess ); + } + + @Override + public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + final UpdateStatement updateStatement = (UpdateStatement) walker.getAST(); + + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final Queryable targetedPersister = fromElement.getQueryable(); + + return new TableBasedUpdateHandlerImpl( factory, walker, getIdTableInfo( targetedPersister ) ) { + @Override + protected void releaseFromUse(Queryable persister, SessionImplementor session) { + if ( afterUseAction == AfterUseAction.NONE ) { + return; + } + + // clean up our id-table rows + cleanUpRows( getIdTableInfo( persister ).getQualifiedIdTableName(), 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) { + final DeleteStatement updateStatement = (DeleteStatement) walker.getAST(); + + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final Queryable targetedPersister = fromElement.getQueryable(); + + return new TableBasedDeleteHandlerImpl( factory, walker, getIdTableInfo( targetedPersister ) ) { + @Override + protected void releaseFromUse(Queryable persister, SessionImplementor session) { + if ( afterUseAction == AfterUseAction.NONE ) { + return; + } + + // clean up our id-table rows + cleanUpRows( getIdTableInfo( persister ).getQualifiedIdTableName(), session ); + } + }; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/IdTableInfoImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/IdTableInfoImpl.java new file mode 100644 index 0000000000..1bc708a31e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/IdTableInfoImpl.java @@ -0,0 +1,44 @@ +/* + * 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.id.global; + +import org.hibernate.hql.spi.id.IdTableInfo; + +/** + * IdTableInfo implementation specific to PersistentTableBulkIdStrategy + * + * @author Steve Ebersole + */ +class IdTableInfoImpl implements IdTableInfo { + private final String idTableName; + + public IdTableInfoImpl(String idTableName) { + this.idTableName = idTableName; + } + + @Override + public String getQualifiedIdTableName() { + return idTableName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/PreparationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/PreparationContextImpl.java new file mode 100644 index 0000000000..41155ab77a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/PreparationContextImpl.java @@ -0,0 +1,40 @@ +/* + * 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.id.global; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl; + +/** + * PreparationContext implementation for GlobalTemporaryTableBulkIdStrategy. Used to collect + * create and drop statements + * + * @author Steve Ebersole + */ +class PreparationContextImpl implements AbstractMultiTableBulkIdStrategyImpl.PreparationContext { + List creationStatements = new ArrayList(); + List dropStatements = new ArrayList(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/AfterUseAction.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/AfterUseAction.java new file mode 100644 index 0000000000..366b00d377 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/AfterUseAction.java @@ -0,0 +1,33 @@ +/* + * 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.id.local; + +/** +* @author Steve Ebersole +*/ +public enum AfterUseAction { + CLEAN, + DROP, + NONE +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/LocalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/Helper.java similarity index 51% rename from hibernate-core/src/main/java/org/hibernate/hql/spi/LocalTemporaryTableBulkIdStrategy.java rename to hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/Helper.java index 1c8b39e930..0c2e505745 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/LocalTemporaryTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/Helper.java @@ -21,129 +21,151 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.hql.spi; +package org.hibernate.hql.spi.id.local; 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.boot.TempTableDdlTransactionHandling; 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.CoreLogging; 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 class Helper { + /** + * Singleton access + */ + public static final Helper INSTANCE = new Helper(); - public static final String SHORT_NAME = "temporary"; + private static final CoreMessageLogger log = CoreLogging.messageLogger( Helper.class ); - 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 ); - } - }; + private Helper() { } - protected void createTempTable(Queryable persister, SessionImplementor session) { + public void createTempTable( + IdTableInfoImpl idTableInfo, + TempTableDdlTransactionHandling ddlTransactionHandling, + 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 { + TemporaryTableCreationWork work = new TemporaryTableCreationWork( idTableInfo, session.getFactory() ); + + if ( ddlTransactionHandling == TempTableDdlTransactionHandling.NONE ) { final Connection connection = session.getTransactionCoordinator() .getJdbcCoordinator() .getLogicalConnection() .getConnection(); + work.execute( connection ); + session.getTransactionCoordinator() .getJdbcCoordinator() .afterStatementExecution(); } + else { + session.getTransactionCoordinator() + .getTransaction() + .createIsolationDelegate() + .delegateWork( work, ddlTransactionHandling == TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT ); + } } - 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 ) ); + private static class TemporaryTableCreationWork extends AbstractWork { + private final IdTableInfoImpl idTableInfo; + private final SessionFactoryImplementor factory; + + private TemporaryTableCreationWork(IdTableInfoImpl idTableInfo, SessionFactoryImplementor factory) { + this.idTableInfo = idTableInfo; + this.factory = factory; + } + + @Override + public void execute(Connection connection) { + try { + Statement statement = connection.createStatement(); + try { + statement.executeUpdate( idTableInfo.getIdTableCreationStatement() ); + factory.getServiceRegistry() + .getService( JdbcServices.class ) + .getSqlExceptionHelper() + .handleAndClearWarnings( statement, WARNING_HANDLER ); + } + finally { + try { + statement.close(); + } + catch( Throwable ignore ) { + // ignore + } + } } - else { + catch( Exception e ) { + log.debug( "unable to create temporary id table [" + e.getMessage() + "]" ); + } + } + } + + private static SqlExceptionHelper.WarningHandler 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 ); + } + }; + + protected void releaseTempTable( + IdTableInfoImpl idTableInfo, + AfterUseAction afterUseAction, + TempTableDdlTransactionHandling ddlTransactionHandling, + SessionImplementor session) { + if ( afterUseAction == AfterUseAction.NONE ) { + return; + } + + if ( afterUseAction == AfterUseAction.DROP ) { + TemporaryTableDropWork work = new TemporaryTableDropWork( idTableInfo, session.getFactory() ); + if ( ddlTransactionHandling == TempTableDdlTransactionHandling.NONE ) { final Connection connection = session.getTransactionCoordinator() .getJdbcCoordinator() .getLogicalConnection() .getConnection(); + work.execute( connection ); + session.getTransactionCoordinator() .getJdbcCoordinator() .afterStatementExecution(); } + else { + session.getTransactionCoordinator() + .getTransaction() + .createIsolationDelegate() + .delegateWork( work, ddlTransactionHandling == TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT ); + } } - else { - // at the very least cleanup the data :) + + if ( afterUseAction == AfterUseAction.CLEAN ) { PreparedStatement ps = null; try { - final String sql = "delete from " + persister.getTemporaryIdTableName(); + final String sql = "delete from " + idTableInfo.getQualifiedIdTableName(); ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false ); session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps ); } @@ -163,25 +185,13 @@ protected void releaseTempTable(Queryable persister, SessionImplementor session) } } - protected boolean shouldIsolateTemporaryTableDDL(SessionImplementor session) { - Boolean dialectVote = session.getFactory().getDialect().performTemporaryTableDDLInIsolation(); - if ( dialectVote != null ) { - return dialectVote; - } - return session.getFactory().getSettings().isDataDefinitionImplicitCommit(); - } + private static class TemporaryTableDropWork extends AbstractWork { + private final IdTableInfoImpl idTableInfo; + private final SessionFactoryImplementor factory; - 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; + private TemporaryTableDropWork(IdTableInfoImpl idTableInfo, SessionFactoryImplementor factory) { + this.idTableInfo = idTableInfo; + this.factory = factory; } @Override @@ -189,61 +199,11 @@ public void execute(Connection connection) { try { Statement statement = connection.createStatement(); try { - statement.executeUpdate( persister.getTemporaryIdTableDDL() ); - persister.getFactory() - .getServiceRegistry() + statement.executeUpdate( idTableInfo.getIdTableDropStatement() ); + factory.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 ); + .handleAndClearWarnings( statement, WARNING_HANDLER ); } finally { try { @@ -259,5 +219,4 @@ public void execute(Connection connection) { } } } - } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/IdTableInfoImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/IdTableInfoImpl.java new file mode 100644 index 0000000000..7d88a77679 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/IdTableInfoImpl.java @@ -0,0 +1,58 @@ +/* + * 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.id.local; + +import org.hibernate.hql.spi.id.IdTableInfo; + +/** + * @author Steve Ebersole + */ +public class IdTableInfoImpl implements IdTableInfo { + private final String idTableName; + + private final String creationStatement; + private final String dropStatement; + + public IdTableInfoImpl( + String idTableName, + String creationStatement, + String dropStatement) { + this.idTableName = idTableName; + this.creationStatement = creationStatement; + this.dropStatement = dropStatement; + } + + @Override + public String getQualifiedIdTableName() { + return idTableName; + } + + public String getIdTableCreationStatement() { + return creationStatement; + } + + public String getIdTableDropStatement() { + return dropStatement; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java new file mode 100644 index 0000000000..62a63f8c78 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java @@ -0,0 +1,176 @@ +/* + * 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.id.local; + +import org.hibernate.boot.TempTableDdlTransactionHandling; +import org.hibernate.boot.spi.MetadataBuildingOptions; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; +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.hql.internal.ast.tree.DeleteStatement; +import org.hibernate.hql.internal.ast.tree.FromElement; +import org.hibernate.hql.internal.ast.tree.UpdateStatement; +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl; +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl.PreparationContext; +import org.hibernate.hql.spi.id.IdTableSupport; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.TableBasedDeleteHandlerImpl; +import org.hibernate.hql.spi.id.TableBasedUpdateHandlerImpl; +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 "local temporary table" (local to each db session). + * + * @author Steve Ebersole + */ +public class LocalTemporaryTableBulkIdStrategy + extends AbstractMultiTableBulkIdStrategyImpl + implements MultiTableBulkIdStrategy { + + public static final String SHORT_NAME = "local_temporary"; + + private final AfterUseAction afterUseAction; + private TempTableDdlTransactionHandling ddlTransactionHandling; + + public LocalTemporaryTableBulkIdStrategy() { + this( + new IdTableSupportStandardImpl() { + @Override + public String getCreateIdTableCommand() { + return "create local temporary table"; + } + }, + AfterUseAction.DROP, + null + ); + } + + public LocalTemporaryTableBulkIdStrategy( + IdTableSupport idTableSupport, + AfterUseAction afterUseAction, + TempTableDdlTransactionHandling ddlTransactionHandling) { + super( idTableSupport ); + this.afterUseAction = afterUseAction; + this.ddlTransactionHandling = ddlTransactionHandling; + } + + @Override + protected void initialize(MetadataBuildingOptions buildingOptions, SessionFactoryOptions sessionFactoryOptions) { + if ( ddlTransactionHandling == null ) { + ddlTransactionHandling = sessionFactoryOptions.getTempTableDdlTransactionHandling(); + } + } + + @Override + protected IdTableInfoImpl buildIdTableInfo( + PersistentClass entityBinding, + Table idTable, + JdbcServices jdbcServices, + MetadataImplementor metadata, + PreparationContext context) { + return new IdTableInfoImpl( + jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( + idTable.getQualifiedTableName(), + jdbcServices.getJdbcEnvironment().getDialect() + ), + buildIdTableCreateStatement( idTable, jdbcServices, metadata ), + buildIdTableDropStatement( idTable, jdbcServices ) + ); + } + + @Override + public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) { + // nothing to do + } + + @Override + public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + final UpdateStatement updateStatement = (UpdateStatement) walker.getAST(); + + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final Queryable targetedPersister = fromElement.getQueryable(); + + final IdTableInfoImpl tableInfo = getIdTableInfo( targetedPersister ); + + return new TableBasedUpdateHandlerImpl( factory, walker, tableInfo ) { + @Override + protected void prepareForUse(Queryable persister, SessionImplementor session) { + Helper.INSTANCE.createTempTable( + tableInfo, + ddlTransactionHandling, + session + ); + } + + @Override + protected void releaseFromUse(Queryable persister, SessionImplementor session) { + Helper.INSTANCE.releaseTempTable( + tableInfo, + afterUseAction, + ddlTransactionHandling, + session + ); + } + }; + } + + @Override + public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + final DeleteStatement updateStatement = (DeleteStatement) walker.getAST(); + + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final Queryable targetedPersister = fromElement.getQueryable(); + + final IdTableInfoImpl tableInfo = getIdTableInfo( targetedPersister ); + + return new TableBasedDeleteHandlerImpl( factory, walker, tableInfo ) { + @Override + protected void prepareForUse(Queryable persister, SessionImplementor session) { + Helper.INSTANCE.createTempTable( + tableInfo, + ddlTransactionHandling, + session + ); + } + + @Override + protected void releaseFromUse(Queryable persister, SessionImplementor session) { + Helper.INSTANCE.releaseTempTable( + tableInfo, + afterUseAction, + ddlTransactionHandling, + session + ); + } + }; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/package-info.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/package-info.java new file mode 100644 index 0000000000..675cc421ba --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/package-info.java @@ -0,0 +1,28 @@ +/* + * 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 + */ + +/** + * Support for multi-table update and delete statements via id-tables. + */ +package org.hibernate.hql.spi.id; diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java new file mode 100644 index 0000000000..9f8944d919 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java @@ -0,0 +1,80 @@ +/* + * 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.id.persistent; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.hql.internal.ast.HqlSqlWalker; +import org.hibernate.hql.spi.id.IdTableInfo; +import org.hibernate.hql.spi.id.TableBasedDeleteHandlerImpl; +import org.hibernate.persister.entity.Queryable; +import org.hibernate.sql.SelectValues; + +import static org.hibernate.hql.spi.id.persistent.Helper.SESSION_ID_COLUMN_NAME; + +/** +* @author Steve Ebersole +*/ +public class DeleteHandlerImpl extends TableBasedDeleteHandlerImpl { + private final IdTableInfo idTableInfo; + + public DeleteHandlerImpl( + SessionFactoryImplementor factory, + HqlSqlWalker walker, + IdTableInfo idTableInfo) { + super( factory, walker, idTableInfo ); + this.idTableInfo = idTableInfo; + } + + @Override + protected void addAnyExtraIdSelectValues(SelectValues selectClause) { + selectClause.addParameter( Types.CHAR, 36 ); + } + + @Override + protected String generateIdSubselect(Queryable persister, IdTableInfo idTableInfo) { + return super.generateIdSubselect( persister, idTableInfo ) + " where " + SESSION_ID_COLUMN_NAME + "=?"; + } + + @Override + protected int handlePrependedParametersOnIdSelection(PreparedStatement ps, SessionImplementor session, int pos) throws SQLException { + Helper.INSTANCE.bindSessionIdentifier( ps, session, pos ); + return 1; + } + + @Override + protected void handleAddedParametersOnDelete(PreparedStatement ps, SessionImplementor session) throws SQLException { + Helper.INSTANCE.bindSessionIdentifier( ps, session, 1 ); + } + + @Override + protected void releaseFromUse(Queryable persister, SessionImplementor session) { + // clean up our id-table rows + Helper.INSTANCE.cleanUpRows( idTableInfo.getQualifiedIdTableName(), session ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/Helper.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/Helper.java new file mode 100644 index 0000000000..7e830b11e6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/Helper.java @@ -0,0 +1,86 @@ +/* + * 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.id.persistent; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.hibernate.HibernateException; +import org.hibernate.JDBCException; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.internal.AbstractSessionImpl; +import org.hibernate.type.UUIDCharType; + +/** + * @author Steve Ebersole + */ +public class Helper { + /** + * Singleton access + */ + public static final Helper INSTANCE = new Helper(); + + public static final String SESSION_ID_COLUMN_NAME = "hib_sess_id"; + + private Helper() { + } + + + public void bindSessionIdentifier(PreparedStatement ps, SessionImplementor session, int position) throws SQLException { + if ( ! AbstractSessionImpl.class.isInstance( session ) ) { + throw new HibernateException( "Only available on SessionImpl instances" ); + } + UUIDCharType.INSTANCE.set( ps, ( (AbstractSessionImpl) session ).getSessionIdentifier(), position, session ); + } + + public void cleanUpRows(String tableName, SessionImplementor session) { + final String sql = "delete from " + tableName + " where " + SESSION_ID_COLUMN_NAME + "=?"; + try { + PreparedStatement ps = null; + try { + ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false ); + bindSessionIdentifier( ps, session, 1 ); + session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps ); + } + finally { + if ( ps != null ) { + try { + session.getTransactionCoordinator().getJdbcCoordinator().release( ps ); + } + catch( Throwable ignore ) { + // ignore + } + } + } + } + catch (SQLException e) { + throw convert( session.getFactory(), e, "Unable to clean up id table [" + tableName + "]", sql ); + } + } + + public JDBCException convert(SessionFactoryImplementor factory, SQLException e, String message, String sql) { + throw factory.getSQLExceptionHelper().convert( e, message, sql ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/IdTableInfoImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/IdTableInfoImpl.java new file mode 100644 index 0000000000..fba0be9497 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/IdTableInfoImpl.java @@ -0,0 +1,44 @@ +/* + * 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.id.persistent; + +import org.hibernate.hql.spi.id.IdTableInfo; + +/** + * IdTableInfo implementation specific to PersistentTableBulkIdStrategy + * + * @author Steve Ebersole + */ +class IdTableInfoImpl implements IdTableInfo { + private final String idTableName; + + public IdTableInfoImpl(String idTableName) { + this.idTableName = idTableName; + } + + @Override + public String getQualifiedIdTableName() { + return idTableName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java new file mode 100644 index 0000000000..d69e97593a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java @@ -0,0 +1,208 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.id.persistent; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.spi.MetadataBuildingOptions; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.cfg.AvailableSettings; +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.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.hql.internal.ast.HqlSqlWalker; +import org.hibernate.hql.internal.ast.tree.DeleteStatement; +import org.hibernate.hql.internal.ast.tree.FromElement; +import org.hibernate.hql.internal.ast.tree.UpdateStatement; +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl; +import org.hibernate.hql.spi.id.IdTableHelper; +import org.hibernate.hql.spi.id.IdTableSupport; +import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Table; +import org.hibernate.persister.entity.Queryable; + +/** + * 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 + extends AbstractMultiTableBulkIdStrategyImpl + implements MultiTableBulkIdStrategy { + + public static final String SHORT_NAME = "persistent"; + + public static final String DROP_ID_TABLES = "hibernate.hql.bulk_id_strategy.persistent.drop_tables"; + public static final String SCHEMA = "hibernate.hql.bulk_id_strategy.persistent.schema"; + public static final String CATALOG = "hibernate.hql.bulk_id_strategy.persistent.catalog"; + + private Identifier catalog; + private Identifier schema; + + private boolean dropIdTables; + private String[] dropTableStatements; + + public PersistentTableBulkIdStrategy() { + this( IdTableSupportStandardImpl.INSTANCE ); + } + + public PersistentTableBulkIdStrategy(IdTableSupport idTableSupport) { + super( idTableSupport ); + } + + @Override + protected PreparationContextImpl buildPreparationContext() { + return new PreparationContextImpl(); + } + + @Override + protected void initialize(MetadataBuildingOptions buildingOptions, SessionFactoryOptions sessionFactoryOptions) { + final StandardServiceRegistry serviceRegistry = buildingOptions.getServiceRegistry(); + final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class ); + final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); + + final String catalogName = configService.getSetting( + CATALOG, + StandardConverters.STRING, + configService.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING ) + ); + final String schemaName = configService.getSetting( + SCHEMA, + StandardConverters.STRING, + configService.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING ) + ); + + this.catalog = jdbcEnvironment.getIdentifierHelper().toIdentifier( catalogName ); + this.schema = jdbcEnvironment.getIdentifierHelper().toIdentifier( schemaName ); + + this.dropIdTables = configService.getSetting( + DROP_ID_TABLES, + StandardConverters.BOOLEAN, + false + ); + } + + @Override + protected QualifiedTableName determineIdTableName( + JdbcEnvironment jdbcEnvironment, + PersistentClass entityBinding) { + return new QualifiedTableName( + catalog, + schema, + super.determineIdTableName( jdbcEnvironment, entityBinding ).getTableName() + ); + } + + @Override + protected void augmentIdTableDefinition(Table idTable) { + Column sessionIdColumn = new Column( Helper.SESSION_ID_COLUMN_NAME ); + sessionIdColumn.setSqlType( "CHAR(36)" ); + sessionIdColumn.setComment( "Used to hold the Hibernate Session identifier" ); + idTable.addColumn( sessionIdColumn ); + } + + @Override + protected IdTableInfoImpl buildIdTableInfo( + PersistentClass entityBinding, + Table idTable, + JdbcServices jdbcServices, + MetadataImplementor metadata, + PreparationContextImpl context) { + final String renderedName = jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( + idTable.getQualifiedTableName(), + jdbcServices.getJdbcEnvironment().getDialect() + ); + + context.creationStatements.add( buildIdTableCreateStatement( idTable, jdbcServices, metadata ) ); + if ( dropIdTables ) { + context.dropStatements.add( buildIdTableDropStatement( idTable, jdbcServices ) ); + } + + return new IdTableInfoImpl( renderedName ); + } + + @Override + protected void finishPreparation( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess, + MetadataImplementor metadata, + PreparationContextImpl context) { + IdTableHelper.INSTANCE.executeIdTableCreationStatements( + context.creationStatements, + jdbcServices, + connectionAccess + ); + + this.dropTableStatements = dropIdTables + ? context.dropStatements.toArray( new String[ context.dropStatements.size() ] ) + : null; + } + + @Override + public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + final UpdateStatement updateStatement = (UpdateStatement) walker.getAST(); + + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final Queryable targetedPersister = fromElement.getQueryable(); + + return new UpdateHandlerImpl( + factory, + walker, + getIdTableInfo( targetedPersister ) + ); + } + + @Override + public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + final DeleteStatement updateStatement = (DeleteStatement) walker.getAST(); + + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final Queryable targetedPersister = fromElement.getQueryable(); + + return new DeleteHandlerImpl( + factory, + walker, + getIdTableInfo( targetedPersister ) + ); + } + + @Override + public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) { + if ( ! dropIdTables ) { + return; + } + + IdTableHelper.INSTANCE.executeIdTableDropStatements( dropTableStatements, jdbcServices, connectionAccess ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PreparationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PreparationContextImpl.java new file mode 100644 index 0000000000..7bbd303a5e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PreparationContextImpl.java @@ -0,0 +1,39 @@ +/* + * 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.id.persistent; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl; + +/** + * PreparationContext implementation for PersistentTableBulkIdStrategy + * + * @author Steve Ebersole + */ +class PreparationContextImpl implements AbstractMultiTableBulkIdStrategyImpl.PreparationContext { + List creationStatements = new ArrayList(); + List dropStatements = new ArrayList(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/UpdateHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/UpdateHandlerImpl.java new file mode 100644 index 0000000000..cd94853a31 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/UpdateHandlerImpl.java @@ -0,0 +1,80 @@ +/* + * 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.id.persistent; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.hql.internal.ast.HqlSqlWalker; +import org.hibernate.hql.spi.id.IdTableInfo; +import org.hibernate.hql.spi.id.TableBasedUpdateHandlerImpl; +import org.hibernate.persister.entity.Queryable; +import org.hibernate.sql.SelectValues; + +import static org.hibernate.hql.spi.id.persistent.Helper.SESSION_ID_COLUMN_NAME; + +/** +* @author Steve Ebersole +*/ +public class UpdateHandlerImpl extends TableBasedUpdateHandlerImpl { + private final IdTableInfo idTableInfo; + + public UpdateHandlerImpl( + SessionFactoryImplementor factory, + HqlSqlWalker walker, + IdTableInfo idTableInfo) { + super( factory, walker, idTableInfo ); + this.idTableInfo = idTableInfo; + } + + @Override + protected void addAnyExtraIdSelectValues(SelectValues selectClause) { + selectClause.addParameter( Types.CHAR, 36 ); + } + + @Override + protected String generateIdSubselect(Queryable persister, IdTableInfo idTableInfo) { + return super.generateIdSubselect( persister, idTableInfo ) + " where " + SESSION_ID_COLUMN_NAME + "=?"; + } + + @Override + protected int handlePrependedParametersOnIdSelection(PreparedStatement ps, SessionImplementor session, int pos) throws SQLException { + Helper.INSTANCE.bindSessionIdentifier( ps, session, pos ); + return 1; + } + + @Override + protected void handleAddedParametersOnUpdate(PreparedStatement ps, SessionImplementor session, int position) throws SQLException { + Helper.INSTANCE.bindSessionIdentifier( ps, session, position ); + } + + @Override + protected void releaseFromUse(Queryable persister, SessionImplementor session) { + // clean up our id-table rows + Helper.INSTANCE.cleanUpRows( idTableInfo.getQualifiedIdTableName(), session ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/package-info.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/package-info.java new file mode 100644 index 0000000000..367faa98f5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/package-info.java @@ -0,0 +1,30 @@ +/* + * 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 contains an implementation of MultiTableBulkIdStrategy based on the use + * of a persistent (ANSI SQL term) table to hold id values. It also holds a "session identifier" + * column which Hibernate manages in order to isolate rows from different sessions. + */ +package org.hibernate.hql.spi.id.persistent; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 087ac1ac64..dbe332e2a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -337,7 +337,6 @@ public MetadataImplementor getMetadata() { Map cacheAccessStrategiesMap = new HashMap(); Map inFlightClassMetadataMap = new HashMap(); for ( final PersistentClass model : metadata.getEntityBindings() ) { - model.prepareTemporaryTables( metadata, getDialect() ); final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName(); // cache region is defined by the root-class in the hierarchy... final EntityRegionAccessStrategy accessStrategy = determineEntityRegionAccessStrategy( @@ -445,7 +444,8 @@ public MetadataImplementor getMetadata() { settings.getMultiTableBulkIdStrategy().prepare( jdbcServices, buildLocalConnectionAccess(), - metadata + metadata, + sessionFactoryOptions ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index cd5e92ace6..83fab7ab63 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -156,7 +156,7 @@ public interface DeprecationLogger { @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).", + " more specific org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy (local_temporary).", id = 90000011 ) void logDeprecationOfTemporaryTableBulkIdStrategy(); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index 9bf86c1fd4..24fa192726 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -100,9 +100,6 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl private boolean customDeleteCallable; private ExecuteUpdateResultCheckStyle deleteCheckStyle; - private String temporaryIdTableName; - private String temporaryIdTableDDL; - private java.util.Map tuplizerImpls; private MappedSuperclass superMappedSuperclass; @@ -798,28 +795,6 @@ public void setSubselectLoadableCollections(boolean hasSubselectCollections) { this.hasSubselectLoadableCollections = hasSubselectCollections; } - public void prepareTemporaryTables(Mapping mapping, Dialect dialect) { - temporaryIdTableName = dialect.generateTemporaryTableName( getTable().getName() ); - if ( dialect.supportsTemporaryTables() ) { - Table table = new Table(); - table.setName( temporaryIdTableName ); - Iterator itr = getTable().getPrimaryKey().getColumnIterator(); - while( itr.hasNext() ) { - Column column = (Column) itr.next(); - table.addColumn( column.clone() ); - } - temporaryIdTableDDL = table.sqlTemporaryTableCreateString( dialect, mapping ); - } - } - - public String getTemporaryIdTableName() { - return temporaryIdTableName; - } - - public String getTemporaryIdTableDDL() { - return temporaryIdTableDDL; - } - public Component getIdentifierMapper() { return identifierMapper; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java index 93d3b4a1f9..39805afd88 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java @@ -41,7 +41,6 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.util.StringHelper; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.tool.hbm2ddl.ColumnMetadata; import org.hibernate.tool.hbm2ddl.TableMetadata; import org.hibernate.tool.schema.extract.spi.ColumnInformation; @@ -497,31 +496,6 @@ public boolean hasPrimaryKey() { return getPrimaryKey() != null; } - public String sqlTemporaryTableCreateString(Dialect dialect, Mapping mapping) throws HibernateException { - StringBuilder buffer = new StringBuilder( dialect.getCreateTemporaryTableString() ) - .append( ' ' ) - .append( name ) - .append( " (" ); - Iterator itr = getColumnIterator(); - while ( itr.hasNext() ) { - final Column column = (Column) itr.next(); - buffer.append( column.getQuotedName( dialect ) ).append( ' ' ); - buffer.append( column.getSqlType( dialect, mapping ) ); - if ( column.isNullable() ) { - buffer.append( dialect.getNullColumnString() ); - } - else { - buffer.append( " not null" ); - } - if ( itr.hasNext() ) { - buffer.append( ", " ); - } - } - buffer.append( ") " ); - buffer.append( dialect.getCreateTemporaryTablePostfix() ); - return buffer.toString(); - } - public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) { StringBuilder buf = new StringBuilder( hasPrimaryKey() ? dialect.getCreateTableString() : dialect.getCreateMultisetTableString() ) .append( ' ' ) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 58ab70d7ea..c98f5e2f83 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -272,9 +272,6 @@ public abstract class AbstractEntityPersister private UniqueEntityLoader queryLoader; - private final String temporaryIdTableName; - private final String temporaryIdTableDDL; - private final Map subclassPropertyAliases = new HashMap(); private final Map subclassPropertyColumnNames = new HashMap(); @@ -791,10 +788,6 @@ public AbstractEntityPersister( // Handle any filters applied to the class level filterHelper = new FilterHelper( persistentClass.getFilters(), factory ); - temporaryIdTableName = persistentClass.getTemporaryIdTableName(); - temporaryIdTableDDL = persistentClass.getTemporaryIdTableDDL(); - - // Check if we can use Reference Cached entities in 2lc // todo : should really validate that the cache access type is read-only boolean refCacheEntries = true; @@ -4409,14 +4402,6 @@ public boolean isMultiTable() { return false; } - public String getTemporaryIdTableName() { - return temporaryIdTableName; - } - - public String getTemporaryIdTableDDL() { - return temporaryIdTableDDL; - } - protected int getPropertySpan() { return entityMetamodel.getPropertySpan(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java index bf92493f04..968c9883ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/Queryable.java @@ -96,22 +96,6 @@ public interface Queryable extends Loadable, PropertyMapping, Joinable { */ public String[][] getContraintOrderedTableKeyColumnClosure(); - /** - * Get the name of the temporary table to be used to (potentially) store id values - * when performing bulk update/deletes. - * - * @return The appropriate temporary table name. - */ - public String getTemporaryIdTableName(); - - /** - * Get the appropriate DDL command for generating the temporary table to - * be used to (potentially) store id values when performing bulk update/deletes. - * - * @return The appropriate temporary table creation command. - */ - public String getTemporaryIdTableDDL(); - /** * Given a property name, determine the number of the table which contains the column * to which this property is mapped. diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TemporaryTableExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TemporaryTableExporter.java deleted file mode 100644 index b618b4d98d..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/TemporaryTableExporter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.tool.schema.internal; - -import java.util.List; - -import org.hibernate.boot.Metadata; -import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.dialect.Dialect; -import org.hibernate.mapping.Column; -import org.hibernate.mapping.Table; - -/** - * @author Strong Liu - */ -public class TemporaryTableExporter extends StandardTableExporter { - public TemporaryTableExporter(Dialect dialect) { - super(dialect); - } - - @Override - public String[] getSqlCreateStrings(Table exportable, Metadata metadata) { - if ( dialect.supportsTemporaryTables() ) { - final String temporaryTableName = generateTableName( dialect, exportable ); - Table temporaryTable = new Table( - Identifier.toIdentifier( exportable.getQuotedCatalog() ), - Identifier.toIdentifier( exportable.getQuotedSchema() ), - Identifier.toIdentifier( temporaryTableName ), - false - ); - //noinspection unchecked - for ( Column column : ( (List) exportable.getPrimaryKey().getColumns() ) ) { - final Column clone = column.clone(); - temporaryTable.addColumn( clone ); - } - return super.getSqlCreateStrings( temporaryTable, metadata ); - } - return null; - } - - public static String generateTableName(final Dialect dialect, final Table primaryTable) { - return dialect.generateTemporaryTableName( primaryTable.getName() ); - } - - @Override - protected String tableCreateString(boolean hasPrimaryKey) { - return dialect.getCreateTemporaryTableString(); - } - - @Override - protected void applyTableCheck(Table table, StringBuilder buf) { - // N/A - } - - @Override - protected void applyComments(Table table, List sqlStrings) { - // N/A - } - - @Override - protected void applyTableTypeString(StringBuilder buf) { - buf.append( " " ).append( dialect.getCreateTemporaryTablePostfix() ); - } - - @Override - public String[] getSqlDropStrings(Table exportable, Metadata metadata) { - return null; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/Oracle8iDialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/Oracle8iDialectTestCase.java index f71efd9842..b38b2cd4a4 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/Oracle8iDialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/Oracle8iDialectTestCase.java @@ -23,6 +23,8 @@ */ package org.hibernate.dialect; +import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl; + import org.junit.Test; import org.hibernate.testing.TestForIssue; @@ -35,7 +37,9 @@ public class Oracle8iDialectTestCase extends BaseUnitTestCase { @Test @TestForIssue(jiraKey = "HHH-9290") public void testTemporaryTableNameTruncation() throws Exception { - String temporaryTableName = new Oracle8iDialect().generateTemporaryTableName( + final AbstractMultiTableBulkIdStrategyImpl strategy = (AbstractMultiTableBulkIdStrategyImpl) new Oracle8iDialect().getDefaultMultiTableBulkIdStrategy(); + + String temporaryTableName = strategy.getIdTableSupport().generateIdTableName( "TABLE_NAME_THAT_EXCEEDS_30_CHARACTERS" ); diff --git a/working-5.0-migration-guide.md b/working-5.0-migration-guide.md index b47bc92e1d..f38ba40e8e 100644 --- a/working-5.0-migration-guide.md +++ b/working-5.0-migration-guide.md @@ -25,7 +25,8 @@ Working list of changes for 5.0 with `org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry`. Applications using custom SqlTypeDescriptor implementations extending the built-in ones and relying on that behavior should be updated to call `SqlTypeDescriptorRegistry#addDescriptor` themselves. - +* Moving `org.hibernate.hql.spi.MultiTableBulkIdStrategy` and friends to new `org.hibernate.hql.spi.id` package + and sub-packages TODOs =====