HHH-9724 - More complete "temp table" coverage and allow Dialects to influence which strategy is used

This commit is contained in:
Steve Ebersole 2015-04-23 15:21:27 -05:00
parent 52589379e1
commit ae43670290
63 changed files with 2181 additions and 1417 deletions

View File

@ -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?
*

View File

@ -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
}

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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) {

View File

@ -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();

View File

@ -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();
}

View File

@ -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;

View File

@ -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

View File

@ -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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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

View File

@ -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.
* <p/>
* 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.
* <p/>
* Possible return values and their meanings:<ul>
* <li>{@link Boolean#TRUE} - Unequivocally, perform the temporary table DDL
* in isolation.</li>
* <li>{@link Boolean#FALSE} - Unequivocally, do <b>not</b> perform the
* temporary table DDL in isolation.</li>
* <li><i>null</i> - defer to the JDBC driver response in regards to
* {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()}</li>
* </ul>
*
* @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<Table> getTableExporter() {
return tableExporter;
}
public Exporter<Table> getTemporaryTableExporter() {
return temporaryTableExporter;
}
public Exporter<Sequence> getSequenceExporter() {
return sequenceExporter;
}

View File

@ -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

View File

@ -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).<p>
//
// 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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

View File

@ -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() {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 );
}
}

View File

@ -108,11 +108,6 @@ public String getIdentityInsertString() {
return "null";
}
@Override
public String getDropTemporaryTableString() {
return "drop temporary table";
}
@Override
public boolean supportsExpectedLobUsagePattern() {
return true;

View File

@ -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";
}
/**

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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<String> tableCleanUpDdl;
@Override
public void prepare(
JdbcServices jdbcServices,
JdbcConnectionAccess connectionAccess,
MetadataImplementor metadata) {
final ConfigurationService configService = metadata.getMetadataBuildingOptions()
.getServiceRegistry()
.getService( ConfigurationService.class );
this.cleanUpTables = configService.getSetting(
CLEAN_UP_ID_TABLES,
StandardConverters.BOOLEAN,
false
);
final List<Table> idTableDefinitions = new ArrayList<Table>();
for ( PersistentClass entityBinding : metadata.getEntityBindings() ) {
if ( !MultiTableBulkIdHelper.INSTANCE.needsIdTable( entityBinding ) ) {
continue;
}
final Table idTableDefinition = generateIdTableDefinition( entityBinding, metadata );
idTableDefinitions.add( idTableDefinition );
if ( cleanUpTables ) {
if ( tableCleanUpDdl == null ) {
tableCleanUpDdl = new ArrayList<String>();
}
tableCleanUpDdl.add( idTableDefinition.sqlDropString( jdbcServices.getDialect(), null, null ) );
}
}
// we export them all at once to better reuse JDBC resources
exportTableDefinitions( idTableDefinitions, jdbcServices, connectionAccess, metadata );
}
protected Table generateIdTableDefinition(PersistentClass entityMapping, MetadataImplementor metadata) {
return MultiTableBulkIdHelper.INSTANCE.generateIdTableDefinition(
entityMapping,
null,
null,
false
);
}
protected void exportTableDefinitions(
List<Table> idTableDefinitions,
JdbcServices jdbcServices,
JdbcConnectionAccess connectionAccess,
MetadataImplementor metadata) {
MultiTableBulkIdHelper.INSTANCE.exportTableDefinitions(
idTableDefinitions,
jdbcServices,
connectionAccess,
metadata
);
}
@Override
public void release(
JdbcServices jdbcServices,
JdbcConnectionAccess connectionAccess) {
if ( ! cleanUpTables ) {
return;
}
MultiTableBulkIdHelper.INSTANCE.cleanupTableDefinitions( jdbcServices, connectionAccess, tableCleanUpDdl );
}
@Override
public UpdateHandler buildUpdateHandler(
SessionFactoryImplementor factory, HqlSqlWalker walker) {
return new TableBasedUpdateHandlerImpl( factory, walker ) {
@Override
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
// clean up our id-table rows
cleanUpRows( determineIdTableName( persister ), session );
}
};
}
private void cleanUpRows(String tableName, SessionImplementor session) {
final String sql = "delete from " + tableName;
PreparedStatement ps = null;
try {
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
}
finally {
if ( ps != null ) {
try {
session.getTransactionCoordinator().getJdbcCoordinator().release( ps );
}
catch( Throwable ignore ) {
// ignore
}
}
}
}
@Override
public DeleteHandler buildDeleteHandler(
SessionFactoryImplementor factory, HqlSqlWalker walker) {
return new TableBasedDeleteHandlerImpl( factory, walker ) {
@Override
protected void releaseFromUse(Queryable persister, SessionImplementor session) {
// clean up our id-table rows
cleanUpRows( determineIdTableName( persister ), session );
}
};
}
}

View File

@ -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<String> tableCleanUpDdl;
/**
* Creates the tables for all the entities that might need it
*
* @param jdbcServices The JdbcService object
* @param connectionAccess Access to the JDBC Connection
* @param metadata Access to the O/RM mapping information
*/
@Override
public void prepare(
JdbcServices jdbcServices,
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<Table> idTableDefinitions = new ArrayList<Table>();
for ( PersistentClass entityBinding : metadata.getEntityBindings() ) {
if ( !MultiTableBulkIdHelper.INSTANCE.needsIdTable( entityBinding ) ) {
continue;
}
final Table idTableDefinition = generateIdTableDefinition( entityBinding, metadata );
idTableDefinitions.add( idTableDefinition );
if ( cleanUpTables ) {
if ( tableCleanUpDdl == null ) {
tableCleanUpDdl = new ArrayList<String>();
}
tableCleanUpDdl.add( idTableDefinition.sqlDropString( jdbcServices.getDialect(), null, null ) );
}
}
// we export them all at once to better reuse JDBC resources
exportTableDefinitions( idTableDefinitions, jdbcServices, connectionAccess, metadata );
}
protected Table generateIdTableDefinition(PersistentClass entityMapping, MetadataImplementor metadata) {
return MultiTableBulkIdHelper.INSTANCE.generateIdTableDefinition(
entityMapping,
catalog,
schema,
true
);
}
protected void exportTableDefinitions(
List<Table> idTableDefinitions,
JdbcServices jdbcServices,
JdbcConnectionAccess connectionAccess,
MetadataImplementor metadata) {
MultiTableBulkIdHelper.INSTANCE.exportTableDefinitions(
idTableDefinitions,
jdbcServices,
connectionAccess,
metadata
);
}
@Override
public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) {
if ( ! cleanUpTables ) {
return;
}
MultiTableBulkIdHelper.INSTANCE.cleanupTableDefinitions( jdbcServices, connectionAccess, tableCleanUpDdl );
}
@Override
public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
return new TableBasedUpdateHandlerImpl( factory, walker, 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 );
}
};
}
}

View File

@ -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 );
}
}

View File

@ -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<TT extends IdTableInfo, CT extends AbstractMultiTableBulkIdStrategyImpl.PreparationContext>
implements MultiTableBulkIdStrategy {
private final IdTableSupport idTableSupport;
private Map<String,TT> idTableInfoMap = new HashMap<String, TT>();
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 {
}
}

View File

@ -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.
* <p/>
* Mainly supports common activities like:<ul>
* <li>processing the original {@code WHERE} clause (if one) - {@link #processWhereClause}</li>
* <li>generating the proper {@code SELECT} clause for the id-table insert - {@link #generateIdInsertSelect}</li>
* <li>generating the sub-select from the id-table - {@link #generateIdSubselect}</li>
* </ul>
*
* @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<ParameterSpecification> 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) {

View File

@ -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<Table> idTableDefinitions,
public void executeIdTableCreationStatements(
List<String> 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<String> 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 );
}
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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";
}
}

View File

@ -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 {
* <li>Adding tables to the passed Mappings, to be picked by by "schema management tools"</li>
* <li>Manually creating the tables immediately through the passed JDBC Connection access</li>
* </ul>
*
* @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.

View File

@ -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<ParameterSpecification> idSelectParameterSpecifications;
private final List<String> 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<String>();
// If many-to-many, delete the FK row in the collection table.

View File

@ -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() );
}
}
}

View File

@ -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<IdTableInfoImpl,PreparationContextImpl>
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 );
}
};
}
}

View File

@ -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;
}
}

View File

@ -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<String> creationStatements = new ArrayList<String>();
List<String> dropStatements = new ArrayList<String>();
}

View File

@ -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
}

View File

@ -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) {
}
}
}
}

View File

@ -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;
}
}

View File

@ -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<IdTableInfoImpl, PreparationContext>
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
);
}
};
}
}

View File

@ -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;

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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<IdTableInfoImpl,PreparationContextImpl>
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 );
}
}

View File

@ -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<String> creationStatements = new ArrayList<String>();
List<String> dropStatements = new ArrayList<String>();
}

View File

@ -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 );
}
}

View File

@ -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;

View File

@ -337,7 +337,6 @@ public MetadataImplementor getMetadata() {
Map cacheAccessStrategiesMap = new HashMap();
Map<String,ClassMetadata> inFlightClassMetadataMap = new HashMap<String,ClassMetadata>();
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
);

View File

@ -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();

View File

@ -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;
}

View File

@ -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( ' ' )

View File

@ -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();
}

View File

@ -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.

View File

@ -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 <stliu@hibernate.org>
*/
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<Column>) 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<String> sqlStrings) {
// N/A
}
@Override
protected void applyTableTypeString(StringBuilder buf) {
buf.append( " " ).append( dialect.getCreateTemporaryTablePostfix() );
}
@Override
public String[] getSqlDropStrings(Table exportable, Metadata metadata) {
return null;
}
}

View File

@ -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"
);

View File

@ -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
=====