* Cleanup temporary table handling in dialects
* Fix insert handling with respect to version, discriminator and generated identifier insertion * Introduce SqmMultiTableInsertStrategy to handle multi-table inserts * Introduce the notion of an "entity table" similar to the "id table" to handle multi-table insertions * Implement table based and cte based multi-table insertion to support all dialects * Implement identifier generator optimizer support for multi-table insert * Fix validation of insert target paths against select item types * Fix some DML validations * Implement over-clause support in SQL AST * Fix multi-valued filter parameter support
This commit is contained in:
parent
c959c7656c
commit
6c4ec95182
|
@ -40,10 +40,11 @@ import org.hibernate.query.CastType;
|
|||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
@ -484,6 +485,11 @@ public class FirebirdDialect extends Dialect {
|
|||
return getVersion() < 400 ? 20 : 52;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return getVersion() < 400 ? 31 : 63;
|
||||
}
|
||||
|
||||
public IdentifierHelper buildIdentifierHelper(
|
||||
IdentifierHelperBuilder builder,
|
||||
DatabaseMetaData dbMetaData) throws SQLException {
|
||||
|
@ -869,16 +875,39 @@ public class FirebirdDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(EntityMappingType entityDescriptor, RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return getVersion() < 210
|
||||
? super.getFallbackSqmMutationStrategy( entityDescriptor, runtimeModelCreationContext )
|
||||
: new GlobalTemporaryTableStrategy(
|
||||
new IdTable( entityDescriptor, name -> "HT_" + name, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ) {
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
: new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ID_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(EntityMappingType entityDescriptor, RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return getVersion() < 210
|
||||
? super.getFallbackSqmInsertStrategy( entityDescriptor, runtimeModelCreationContext )
|
||||
: new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.Replacer;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
|
@ -33,10 +32,13 @@ import org.hibernate.query.spi.QueryEngine;
|
|||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
|
@ -387,23 +389,55 @@ public class InformixDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableStrategy(
|
||||
new IdTable( rootEntityDescriptor, basename -> "HT_" + basename, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( true, this::getTypeName ) {
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "with no log";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return "create temp table";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
return "with no log";
|
||||
public AfterUseAction getTemporaryTableAfterUseAction() {
|
||||
return AfterUseAction.NONE;
|
||||
}
|
||||
},
|
||||
AfterUseAction.NONE,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
|
||||
@Override
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,10 +31,11 @@ import org.hibernate.query.spi.QueryEngine;
|
|||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
|
@ -412,23 +413,46 @@ public class IngresDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable( rootEntityDescriptor, name -> "session." + name, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ) {
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
name -> "session." + TemporaryTable.ID_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> "session." + TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit preserve rows with norecovery";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return "declare global temporary table";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -31,10 +31,11 @@ import org.hibernate.query.IntervalType;
|
|||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ForUpdateFragment;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -294,43 +295,52 @@ public class TeradataDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable( rootEntityDescriptor, basename -> "HT_" + basename, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ) {
|
||||
@Override
|
||||
public String getCreateOptions() {
|
||||
return "on commit preserve rows";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String generateIdTableName(String baseName) {
|
||||
// return IdTableSupportStandardImpl.INSTANCE.generateIdTableName( baseName );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getCreateIdTableCommand() {
|
||||
// return "create global temporary table";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getCreateIdTableStatementOptions() {
|
||||
// return " on commit preserve rows";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getDropIdTableCommand() {
|
||||
// return "drop table";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getTruncateIdTableCommand() {
|
||||
// return "delete from";
|
||||
// }
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit preserve rows";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxAliasLength() {
|
||||
// Max identifier length is 30, but Hibernate needs to add "uniqueing info" so we account for that
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCascadeDelete() {
|
||||
|
|
|
@ -25,10 +25,11 @@ import org.hibernate.persister.entity.Lockable;
|
|||
import org.hibernate.query.IntervalType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
@ -313,24 +314,42 @@ public class TimesTenDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable(
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
name -> name.length() > 30 ? name.substring( 0, 30 ) : name,
|
||||
name -> TemporaryTable.ID_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ) {
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
|
||||
// TimesTen has no known variation of a "SELECT ... FOR UPDATE" syntax...
|
||||
|
@ -354,6 +373,17 @@ public class TimesTenDialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxAliasLength() {
|
||||
// Max identifier length is 30, but Hibernate needs to add "uniqueing info" so we account for that
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCircularCascadeDeleteConstraints() {
|
||||
return false;
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.hibernate.query.criteria.ValueHandlingMode;
|
|||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
|
@ -217,6 +218,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
// Queries
|
||||
private HqlTranslator hqlTranslator;
|
||||
private SqmMultiTableMutationStrategy sqmMultiTableMutationStrategy;
|
||||
private SqmMultiTableInsertStrategy sqmMultiTableInsertStrategy;
|
||||
private SqmFunctionRegistry sqmFunctionRegistry;
|
||||
private SqmTranslatorFactory sqmTranslatorFactory;
|
||||
private Boolean useOfJdbcNamedParametersEnabled;
|
||||
|
@ -430,6 +432,18 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
strategySelector
|
||||
);
|
||||
|
||||
final String sqmInsertStrategyImplName = ConfigurationHelper.extractValue(
|
||||
AvailableSettings.QUERY_MULTI_TABLE_INSERT_STRATEGY,
|
||||
configurationSettings,
|
||||
() -> null
|
||||
);
|
||||
|
||||
this.sqmMultiTableInsertStrategy = resolveSqmInsertStrategy(
|
||||
sqmInsertStrategyImplName,
|
||||
serviceRegistry,
|
||||
strategySelector
|
||||
);
|
||||
|
||||
this.useOfJdbcNamedParametersEnabled = cfgService.getSetting( CALLABLE_NAMED_PARAMS_ENABLED, BOOLEAN, true );
|
||||
|
||||
this.querySubstitutions = ConfigurationHelper.toMap( QUERY_SUBSTITUTIONS, " ,=;:\n\t\r\f", configurationSettings );
|
||||
|
@ -658,6 +672,54 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
);
|
||||
}
|
||||
|
||||
private SqmMultiTableInsertStrategy resolveSqmInsertStrategy(
|
||||
String strategyName,
|
||||
StandardServiceRegistry serviceRegistry,
|
||||
StrategySelector strategySelector) {
|
||||
if ( strategyName == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return strategySelector.resolveStrategy(
|
||||
SqmMultiTableInsertStrategy.class,
|
||||
strategyName,
|
||||
(SqmMultiTableInsertStrategy) null,
|
||||
strategyClass -> {
|
||||
Constructor<SqmMultiTableInsertStrategy> dialectConstructor = null;
|
||||
Constructor<SqmMultiTableInsertStrategy> emptyConstructor = null;
|
||||
// todo (6.0) : formalize the allowed constructor parameterizations
|
||||
for ( Constructor<?> declaredConstructor : strategyClass.getDeclaredConstructors() ) {
|
||||
final Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
|
||||
if ( parameterTypes.length == 1 && parameterTypes[0] == Dialect.class ) {
|
||||
dialectConstructor = (Constructor<SqmMultiTableInsertStrategy>) declaredConstructor;
|
||||
break;
|
||||
}
|
||||
else if ( parameterTypes.length == 0 ) {
|
||||
emptyConstructor = (Constructor<SqmMultiTableInsertStrategy>) declaredConstructor;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if ( dialectConstructor != null ) {
|
||||
return dialectConstructor.newInstance(
|
||||
serviceRegistry.getService( JdbcServices.class ).getDialect()
|
||||
);
|
||||
}
|
||||
else if ( emptyConstructor != null ) {
|
||||
return emptyConstructor.newInstance();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new StrategySelectionException(
|
||||
String.format( "Could not instantiate named strategy class [%s]", strategyClass.getName() ),
|
||||
e
|
||||
);
|
||||
}
|
||||
throw new IllegalArgumentException( "Cannot instantiate the class [" + strategyClass.getName() + "] because it does not have a constructor that accepts a dialect or an empty constructor!" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private HqlTranslator resolveHqlTranslator(
|
||||
String producerName,
|
||||
StandardServiceRegistry serviceRegistry,
|
||||
|
@ -898,6 +960,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return sqmMultiTableMutationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getCustomSqmMultiTableInsertStrategy() {
|
||||
return sqmMultiTableInsertStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseOfJdbcNamedParametersEnabled() {
|
||||
return this.useOfJdbcNamedParametersEnabled;
|
||||
|
|
|
@ -26,10 +26,10 @@ import org.hibernate.cache.internal.SimpleCacheKeysFactory;
|
|||
import org.hibernate.cache.spi.CacheKeysFactory;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.PersistentTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl;
|
||||
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
|
||||
|
@ -171,23 +171,23 @@ public class StrategySelectorBuilder {
|
|||
private void addSqmMultiTableMutationStrategies(StrategySelectorImpl strategySelector) {
|
||||
strategySelector.registerStrategyImplementor(
|
||||
SqmMultiTableMutationStrategy.class,
|
||||
CteStrategy.SHORT_NAME,
|
||||
CteStrategy.class
|
||||
CteMutationStrategy.SHORT_NAME,
|
||||
CteMutationStrategy.class
|
||||
);
|
||||
strategySelector.registerStrategyImplementor(
|
||||
SqmMultiTableMutationStrategy.class,
|
||||
GlobalTemporaryTableStrategy.SHORT_NAME,
|
||||
GlobalTemporaryTableStrategy.class
|
||||
GlobalTemporaryTableMutationStrategy.SHORT_NAME,
|
||||
GlobalTemporaryTableMutationStrategy.class
|
||||
);
|
||||
strategySelector.registerStrategyImplementor(
|
||||
SqmMultiTableMutationStrategy.class,
|
||||
LocalTemporaryTableStrategy.SHORT_NAME,
|
||||
LocalTemporaryTableStrategy.class
|
||||
LocalTemporaryTableMutationStrategy.SHORT_NAME,
|
||||
LocalTemporaryTableMutationStrategy.class
|
||||
);
|
||||
strategySelector.registerStrategyImplementor(
|
||||
SqmMultiTableMutationStrategy.class,
|
||||
PersistentTableStrategy.SHORT_NAME,
|
||||
PersistentTableStrategy.class
|
||||
PersistentTableMutationStrategy.SHORT_NAME,
|
||||
PersistentTableMutationStrategy.class
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.query.criteria.ValueHandlingMode;
|
|||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
|
@ -129,6 +130,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
return delegate.getCustomSqmMultiTableMutationStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getCustomSqmMultiTableInsertStrategy() {
|
||||
return delegate.getCustomSqmMultiTableInsertStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementInspector getStatementInspector() {
|
||||
return delegate.getStatementInspector();
|
||||
|
|
|
@ -950,6 +950,13 @@ public interface AvailableSettings {
|
|||
*/
|
||||
String QUERY_MULTI_TABLE_MUTATION_STRATEGY = "hibernate.query.mutation_strategy";
|
||||
|
||||
/**
|
||||
* Defines the "global" strategy to use for handling HQL and Criteria insert queries.
|
||||
*
|
||||
* Names the {@link org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy} to use.
|
||||
*/
|
||||
String QUERY_MULTI_TABLE_INSERT_STRATEGY = "hibernate.query.insert_strategy";
|
||||
|
||||
/**
|
||||
* A comma-separated list of token substitutions to use when translating a Hibernate
|
||||
* query to SQL
|
||||
|
|
|
@ -1179,6 +1179,11 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
return 128;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 127;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimitHandler getLimitHandler() {
|
||||
return LimitOffsetLimitHandler.INSTANCE;
|
||||
|
|
|
@ -8,9 +8,9 @@ package org.hibernate.dialect;
|
|||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.function.CastingConcatFunction;
|
||||
import org.hibernate.dialect.function.TransactSQLStrFunction;
|
||||
import org.hibernate.query.NullOrdering;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
|
||||
|
@ -20,11 +20,15 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.TrimSpec;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -126,6 +130,15 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
|
|||
queryEngine.getSqmFunctionRegistry().register( "least", new CaseLeastGreatestEmulation( true ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "greatest", new CaseLeastGreatestEmulation( false ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "str", new TransactSQLStrFunction( queryEngine.getTypeConfiguration() ) );
|
||||
queryEngine.getSqmFunctionRegistry().register(
|
||||
"concat",
|
||||
new CastingConcatFunction(
|
||||
this,
|
||||
"+",
|
||||
SqlAstNodeRenderingMode.DEFAULT,
|
||||
queryEngine.getTypeConfiguration()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -259,21 +272,53 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableStrategy(
|
||||
new IdTable( entityDescriptor, basename -> "#" + basename, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( true, this::getTypeName ) {
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
return "create table";
|
||||
}
|
||||
},
|
||||
// // sql-server, at least needed this dropped after use; strange!
|
||||
AfterUseAction.DROP,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
basename -> '#' + TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> '#' + TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return "create table";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AfterUseAction getTemporaryTableAfterUseAction() {
|
||||
// sql-server, at least needed this dropped after use; strange!
|
||||
return AfterUseAction.DROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectGUIDString() {
|
||||
return "select newid()";
|
||||
|
|
|
@ -348,6 +348,11 @@ public class CockroachDialect extends Dialect {
|
|||
return NationalizationSupport.IMPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 63;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(
|
||||
SqlAppender appender,
|
||||
|
|
|
@ -31,7 +31,9 @@ import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
|||
import org.hibernate.query.IntervalType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
|
@ -169,8 +171,20 @@ public class DB2Dialect extends Dialect {
|
|||
CommonFunctionFactory.trim2( queryEngine );
|
||||
CommonFunctionFactory.space( queryEngine );
|
||||
CommonFunctionFactory.repeat( queryEngine );
|
||||
CommonFunctionFactory.substr( queryEngine );
|
||||
//also natively supports ANSI-style substring()
|
||||
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substr" )
|
||||
.setInvariantType(
|
||||
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
|
||||
)
|
||||
.setArgumentCountBetween( 2, 4 )
|
||||
.setArgumentListSignature( "(string, start[, length[, units]])" )
|
||||
.register();
|
||||
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substring" )
|
||||
.setInvariantType(
|
||||
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
|
||||
)
|
||||
.setArgumentCountBetween( 2, 4 )
|
||||
.setArgumentListSignature( "(string{ from|,} start[{ for|,} length[, units]])" )
|
||||
.register();
|
||||
CommonFunctionFactory.translate( queryEngine );
|
||||
CommonFunctionFactory.bitand( queryEngine );
|
||||
CommonFunctionFactory.bitor( queryEngine );
|
||||
|
@ -460,7 +474,14 @@ public class DB2Dialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new CteStrategy( rootEntityDescriptor, runtimeModelCreationContext );
|
||||
return new CteMutationStrategy( rootEntityDescriptor, runtimeModelCreationContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new CteInsertStrategy( rootEntityDescriptor, runtimeModelCreationContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -576,6 +597,11 @@ public class DB2Dialect extends Dialect {
|
|||
return uniqueDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimitHandler getLimitHandler() {
|
||||
return limitHandler;
|
||||
|
|
|
@ -8,11 +8,10 @@ package org.hibernate.dialect;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.DerbyConcatFunction;
|
||||
import org.hibernate.dialect.function.CastingConcatFunction;
|
||||
import org.hibernate.dialect.function.DerbyLpadEmulation;
|
||||
import org.hibernate.dialect.function.DerbyRpadEmulation;
|
||||
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
|
||||
|
@ -36,10 +35,13 @@ import org.hibernate.query.CastType;
|
|||
import org.hibernate.query.IntervalType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
|
@ -56,6 +58,7 @@ import org.hibernate.type.BasicType;
|
|||
import org.hibernate.type.BasicTypeRegistry;
|
||||
import org.hibernate.type.JavaObjectType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.BigDecimalJavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.jdbc.DecimalJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ObjectNullResolvingJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
|
@ -199,6 +202,8 @@ public class DerbyDialect extends Dialect {
|
|||
"||",
|
||||
getCastTypeName( stringType, null, null, null )
|
||||
);
|
||||
// AVG by default uses the input type, so we possibly need to cast the argument type, hence a special function
|
||||
CommonFunctionFactory.avg_castingNonDoubleArguments( this, queryEngine, SqlAstNodeRenderingMode.DEFAULT );
|
||||
|
||||
CommonFunctionFactory.concat_pipeOperator( queryEngine );
|
||||
CommonFunctionFactory.cot( queryEngine );
|
||||
|
@ -220,13 +225,22 @@ public class DerbyDialect extends Dialect {
|
|||
CommonFunctionFactory.leftRight_substrLength( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
CommonFunctionFactory.power_expLn( queryEngine );
|
||||
CommonFunctionFactory.bitLength_pattern( queryEngine, "length(?1)*8" );
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "round", "floor(?1*1e?2+0.5)/1e?2")
|
||||
.setReturnTypeResolver( useArgType(1) )
|
||||
.setExactArgumentCount( 2 )
|
||||
.register();
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatFunction( this, queryEngine.getTypeConfiguration() ) );
|
||||
queryEngine.getSqmFunctionRegistry().register(
|
||||
"concat",
|
||||
new CastingConcatFunction(
|
||||
this,
|
||||
"||",
|
||||
SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER,
|
||||
queryEngine.getTypeConfiguration()
|
||||
)
|
||||
);
|
||||
|
||||
//no way I can see to pad with anything other than spaces
|
||||
queryEngine.getSqmFunctionRegistry().register( "lpad", new DerbyLpadEmulation( queryEngine.getTypeConfiguration() ) );
|
||||
|
@ -324,8 +338,9 @@ public class DerbyDialect extends Dialect {
|
|||
case FLOAT:
|
||||
case DOUBLE:
|
||||
// Derby can't cast to char directly, but needs to be cast to decimal first...
|
||||
return "cast(trim(cast(cast(?1 as decimal) as char(254))) as ?2)";
|
||||
return "cast(trim(cast(cast(?1 as decimal(" + getDefaultDecimalPrecision() + "," + BigDecimalJavaTypeDescriptor.INSTANCE.getDefaultSqlScale( this, null ) + ")) as char(254))) as ?2)";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
case FIXED:
|
||||
return "cast(trim(cast(?1 as char(254))) as ?2)";
|
||||
}
|
||||
|
@ -773,7 +788,7 @@ public class DerbyDialect extends Dialect {
|
|||
* The DECLARE GLOBAL TEMPORARY TABLE statement defines a temporary table for the current connection.
|
||||
* </pre>
|
||||
*
|
||||
* {@link DB2Dialect} returns a {@link org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy} that
|
||||
* {@link DB2Dialect} returns a {@link GlobalTemporaryTableMutationStrategy} that
|
||||
* will make temporary tables created at startup and hence unavailable for subsequent connections.<br/>
|
||||
* see HHH-10238.
|
||||
*/
|
||||
|
@ -781,32 +796,65 @@ public class DerbyDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableStrategy(
|
||||
new IdTable(
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
basename -> "session.HT_" + basename,
|
||||
basename -> "session." + TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
() -> new TempIdTableExporter( true, this::getTypeName ) {
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> "session." + TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "not logged";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemporaryTablePrimaryKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return "declare global temporary table";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
return "not logged";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsPartitionBy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWindowFunctions() {
|
||||
// It seems at least the row_number function is supported as of 10.4
|
||||
return getVersion() >= 1040;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableExporter;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.internal.util.MathHelper;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
|
@ -60,10 +62,14 @@ import org.hibernate.query.TrimSpec;
|
|||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.PersistentTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.PhysicalIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.temptable.StandardTemporaryTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
@ -711,6 +717,8 @@ public abstract class Dialect implements ConversionContext {
|
|||
)
|
||||
);
|
||||
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "current_instant", "instant" ); //deprecated legacy!
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "sql", new SqlFunction() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1481,6 +1489,11 @@ public abstract class Dialect implements ConversionContext {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean supportsTemporaryTablePrimaryKey() {
|
||||
// Most databases do
|
||||
return true;
|
||||
}
|
||||
|
||||
// limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
/**
|
||||
|
@ -1833,10 +1846,27 @@ public abstract class Dialect implements ConversionContext {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new PersistentTableStrategy(
|
||||
new IdTable( entityDescriptor, name -> name, this, runtimeModelCreationContext ),
|
||||
AfterUseAction.CLEAN,
|
||||
PhysicalIdTableExporter::new,
|
||||
return new PersistentTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new PersistentTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
@ -2122,6 +2152,15 @@ public abstract class Dialect implements ConversionContext {
|
|||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the maximum identifier length supported by the dialect?
|
||||
*
|
||||
* @return The maximum length.
|
||||
*/
|
||||
public int getMaxIdentifierLength() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL literal value to which this database maps boolean values.
|
||||
*
|
||||
|
@ -2243,12 +2282,13 @@ public abstract class Dialect implements ConversionContext {
|
|||
|
||||
// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private StandardTableExporter tableExporter = new StandardTableExporter( this );
|
||||
protected StandardSequenceExporter sequenceExporter = new StandardSequenceExporter( this );
|
||||
private StandardIndexExporter indexExporter = new StandardIndexExporter( this );
|
||||
private StandardForeignKeyExporter foreignKeyExporter = new StandardForeignKeyExporter( this );
|
||||
private StandardUniqueKeyExporter uniqueKeyExporter = new StandardUniqueKeyExporter( this );
|
||||
private StandardAuxiliaryDatabaseObjectExporter auxiliaryObjectExporter = new StandardAuxiliaryDatabaseObjectExporter( this );
|
||||
private final StandardTableExporter tableExporter = new StandardTableExporter( this );
|
||||
private final StandardSequenceExporter sequenceExporter = new StandardSequenceExporter( this );
|
||||
private final StandardIndexExporter indexExporter = new StandardIndexExporter( this );
|
||||
private final StandardForeignKeyExporter foreignKeyExporter = new StandardForeignKeyExporter( this );
|
||||
private final StandardUniqueKeyExporter uniqueKeyExporter = new StandardUniqueKeyExporter( this );
|
||||
private final StandardAuxiliaryDatabaseObjectExporter auxiliaryObjectExporter = new StandardAuxiliaryDatabaseObjectExporter( this );
|
||||
private final StandardTemporaryTableExporter temporaryTableExporter = new StandardTemporaryTableExporter( this );
|
||||
|
||||
public Exporter<Table> getTableExporter() {
|
||||
return tableExporter;
|
||||
|
@ -2274,6 +2314,61 @@ public abstract class Dialect implements ConversionContext {
|
|||
return auxiliaryObjectExporter;
|
||||
}
|
||||
|
||||
public TemporaryTableExporter getTemporaryTableExporter() {
|
||||
return temporaryTableExporter;
|
||||
}
|
||||
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.PERSISTENT;
|
||||
}
|
||||
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
final TemporaryTableKind kind = getSupportedTemporaryTableKind();
|
||||
switch ( kind ) {
|
||||
case PERSISTENT:
|
||||
return "create table";
|
||||
case LOCAL:
|
||||
return "create local temporary table";
|
||||
case GLOBAL:
|
||||
return "create global temporary table";
|
||||
}
|
||||
throw new UnsupportedOperationException( "Unsupported kind: " + kind );
|
||||
}
|
||||
|
||||
public String getTemporaryTableDropCommand() {
|
||||
return "drop table";
|
||||
}
|
||||
|
||||
public String getTemporaryTableTruncateCommand() {
|
||||
return "delete from";
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation to be appended to the end of each COLUMN clause for temporary tables.
|
||||
*
|
||||
* @param sqlTypeCode The SQL type code
|
||||
* @return The annotation to be appended (e.g. "COLLATE DATABASE_DEFAULT" in SQLServer SQL)
|
||||
*/
|
||||
public String getCreateTemporaryTableColumnAnnotation(int sqlTypeCode) {
|
||||
return "";
|
||||
}
|
||||
|
||||
public TempTableDdlTransactionHandling getTemporaryTableDdlTransactionHandling() {
|
||||
return TempTableDdlTransactionHandling.NONE;
|
||||
}
|
||||
|
||||
public AfterUseAction getTemporaryTableAfterUseAction() {
|
||||
return AfterUseAction.CLEAN;
|
||||
}
|
||||
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this dialect support catalog creation?
|
||||
*
|
||||
|
@ -3781,14 +3876,4 @@ public abstract class Dialect implements ConversionContext {
|
|||
public TimeZoneSupport getTimeZoneSupport() {
|
||||
return TimeZoneSupport.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation to be appended to the end of each COLUMN clause for temporary tables.
|
||||
*
|
||||
* @param sqlTypeCode The SQL type code
|
||||
* @return The annotation to be appended (e.g. "COLLATE DATABASE_DEFAULT" in SQLServer SQL)
|
||||
*/
|
||||
public String getCreateTemporaryTableColumnAnnotation(int sqlTypeCode) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.hibernate.query.FetchClauseType;
|
|||
import org.hibernate.query.IntervalType;
|
||||
import org.hibernate.query.NullOrdering;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.hint.IndexQueryHintHandler;
|
||||
|
@ -39,9 +38,12 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
|
@ -375,15 +377,42 @@ public class H2Dialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableStrategy(
|
||||
new IdTable( entityDescriptor, basename -> "HT_" + basename, this, runtimeModelCreationContext ),
|
||||
this::getTypeName,
|
||||
AfterUseAction.CLEAN,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
|
||||
return EXTRACTOR;
|
||||
|
|
|
@ -12,10 +12,11 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.PhysicalIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
|
@ -127,29 +128,53 @@ public class HANAColumnStoreDialect extends AbstractHANADialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable( entityDescriptor, basename -> "HT_" + basename, this, runtimeModelCreationContext ),
|
||||
() -> new PhysicalIdTableExporter() {
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
return "create global temporary column table";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTruncateIdTableCommand() {
|
||||
return "truncate table";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
// We use a row table for temporary tables here because HANA doesn't support UPDATE on temporary column tables
|
||||
return "create global temporary row table";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableTruncateCommand() {
|
||||
return "truncate table";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsAsciiStringTypes() {
|
||||
if ( version >= 400 ) {
|
||||
|
|
|
@ -9,10 +9,11 @@ package org.hibernate.dialect;
|
|||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.PhysicalIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
|
||||
/**
|
||||
|
@ -49,22 +50,50 @@ public class HANARowStoreDialect extends AbstractHANADialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable( entityDescriptor, basename -> "HT_" + basename, this, runtimeModelCreationContext ),
|
||||
() -> new PhysicalIdTableExporter() {
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return "create global temporary row table";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
public String getTemporaryTableTruncateCommand() {
|
||||
return "truncate table";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.query.IntervalType;
|
||||
import org.hibernate.query.NullOrdering;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.identity.HSQLIdentityColumnSupport;
|
||||
|
@ -49,11 +48,15 @@ import org.hibernate.persister.entity.Lockable;
|
|||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -514,33 +517,93 @@ public class HSQLDialect extends Dialect {
|
|||
// can happen in the middle of a transaction
|
||||
|
||||
if ( version < 200 ) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable( rootEntityDescriptor, name -> "HT_" + name, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ),
|
||||
// Version 1.8 GLOBAL TEMPORARY table definitions persist beyond the end
|
||||
// of the session (by default, data is cleared at commit).
|
||||
AfterUseAction.CLEAN,
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new LocalTemporaryTableStrategy(
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
// 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_)
|
||||
new IdTable( rootEntityDescriptor, name -> "MODULE.HT_" + name, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( true, this::getTypeName ) {
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
return "declare local temporary table";
|
||||
}
|
||||
},
|
||||
AfterUseAction.DROP,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
basename -> "MODULE." + TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
|
||||
// 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
|
||||
|
||||
if ( version < 200 ) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
// 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_)
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> "MODULE." + TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return version < 200 ? TemporaryTableKind.GLOBAL : TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return version < 200 ? super.getTemporaryTableCreateCommand() : "declare local temporary table";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AfterUseAction getTemporaryTableAfterUseAction() {
|
||||
// Version 1.8 GLOBAL TEMPORARY table definitions persist beyond the end
|
||||
// of the session (by default, data is cleared at commit).
|
||||
return version < 200 ? AfterUseAction.CLEAN : AfterUseAction.DROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return version < 200 ? BeforeUseAction.NONE : BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.hibernate.query.CastType;
|
|||
import org.hibernate.query.IntervalType;
|
||||
import org.hibernate.query.NullOrdering;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.hint.IndexQueryHintHandler;
|
||||
|
@ -44,10 +43,13 @@ import org.hibernate.metamodel.mapping.SqlExpressable;
|
|||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -696,23 +698,67 @@ public class MySQLDialect extends Dialect {
|
|||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
|
||||
return new LocalTemporaryTableStrategy(
|
||||
new IdTable( rootEntityDescriptor, basename -> "HT_" + basename, this, runtimeModelCreationContext ),
|
||||
() -> new TempIdTableExporter( true, this::getTypeName ) {
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateCommand() {
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateCommand() {
|
||||
return "create temporary table if not exists";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDropCommand() {
|
||||
public String getTemporaryTableDropCommand() {
|
||||
return "drop temporary table";
|
||||
}
|
||||
},
|
||||
AfterUseAction.DROP,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
|
||||
@Override
|
||||
public AfterUseAction getTemporaryTableAfterUseAction() {
|
||||
return AfterUseAction.DROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxAliasLength() {
|
||||
// Max alias length is 256, but Hibernate needs to add "uniqueing info" so we account for that
|
||||
return 246;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,10 +42,11 @@ import org.hibernate.query.SemanticException;
|
|||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.GlobalTemporaryTableStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
|
@ -902,24 +903,42 @@ public class OracleDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable(
|
||||
return new GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
rootEntityDescriptor,
|
||||
name -> "HT_" + ( name.length() > 27 ? name.substring( 0, 27 ) : name ),
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ) {
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
},
|
||||
AfterUseAction.CLEAN,
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
rootEntityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemporaryTableCreateOptions() {
|
||||
return "on commit delete rows";
|
||||
}
|
||||
|
||||
/**
|
||||
* For Oracle, the FOR UPDATE clause cannot be applied when using ORDER BY, DISTINCT or views.
|
||||
*
|
||||
|
@ -969,10 +988,15 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public int getMaxAliasLength() {
|
||||
// Oracle's max identifier length is 30, but Hibernate needs to add "uniqueing info" so we account for that,
|
||||
// Max identifier length is 30, but Hibernate needs to add "uniqueing info" so we account for that
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementSupport getCallableStatementSupport() {
|
||||
// Oracle supports returning cursors
|
||||
|
|
|
@ -20,10 +20,13 @@ import org.hibernate.sql.ast.spi.SqlSelection;
|
|||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.Over;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.ValuesTableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.Values;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -244,6 +247,52 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderValuesTableReference(ValuesTableReference tableReference) {
|
||||
final List<Values> valuesList = tableReference.getValuesList();
|
||||
if ( valuesList.size() < 2 ) {
|
||||
super.renderValuesTableReference( tableReference );
|
||||
}
|
||||
else {
|
||||
append( '(' );
|
||||
// Oracle doesn't support a multi-values insert
|
||||
// So we render a select union emulation instead
|
||||
final Stack<Clause> clauseStack = getClauseStack();
|
||||
clauseStack.push( Clause.VALUES );
|
||||
try {
|
||||
// We render the first select statement with aliases
|
||||
clauseStack.push( Clause.SELECT );
|
||||
|
||||
try {
|
||||
appendSql( "select " );
|
||||
|
||||
renderCommaSeparatedSelectExpression(
|
||||
valuesList.get( 0 ).getExpressions(),
|
||||
tableReference.getColumnNames()
|
||||
);
|
||||
appendSql( getFromDualForSelectOnly() );
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
// The others, without the aliases
|
||||
for ( int i = 1; i < valuesList.size(); i++ ) {
|
||||
appendSql( " union all " );
|
||||
renderExpressionsAsSubquery( valuesList.get( i ).getExpressions() );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
append( ')' );
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
if ( identificationVariable != null ) {
|
||||
append( WHITESPACE );
|
||||
append( tableReference.getIdentificationVariable() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQueryGroup(QueryGroup queryGroup) {
|
||||
if ( shouldEmulateFetchClause( queryGroup ) ) {
|
||||
|
@ -287,6 +336,22 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOver(Over over) {
|
||||
final Expression expression = over.getExpression();
|
||||
if ( expression instanceof FunctionExpression && "row_number".equals( ( (FunctionExpression) expression ).getFunctionName() ) ) {
|
||||
if ( over.getPartitions().isEmpty() && over.getOrderList().isEmpty()
|
||||
&& over.getStartKind() == Over.FrameKind.UNBOUNDED_PRECEDING
|
||||
&& over.getEndKind() == Over.FrameKind.CURRENT_ROW
|
||||
&& over.getExclusion() == Over.FrameExclusion.NO_OTHERS ) {
|
||||
// Oracle doesn't allow an empty over clause for the row_number() function
|
||||
append( "rownum" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.visitOver( over );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
|
||||
renderComparisonEmulateDecode( lhs, operator, rhs );
|
||||
|
|
|
@ -57,7 +57,9 @@ import org.hibernate.query.IntervalType;
|
|||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -617,7 +619,14 @@ public class PostgreSQLDialect extends Dialect {
|
|||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new CteStrategy( rootEntityDescriptor, runtimeModelCreationContext );
|
||||
return new CteMutationStrategy( rootEntityDescriptor, runtimeModelCreationContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new CteInsertStrategy( rootEntityDescriptor, runtimeModelCreationContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -746,6 +755,11 @@ public class PostgreSQLDialect extends Dialect {
|
|||
return NationalizationSupport.IMPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 63;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsJdbcConnectionLobCreation(DatabaseMetaData databaseMetaData) {
|
||||
return false;
|
||||
|
|
|
@ -164,6 +164,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
return 2_147_483_647;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
super.contributeTypes( typeContributions, serviceRegistry );
|
||||
|
@ -288,7 +293,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
@Override
|
||||
public String currentDate() {
|
||||
return currentTimestamp();
|
||||
return "convert(date,getdate())";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -494,6 +494,11 @@ public class SybaseASEDialect extends SybaseDialect {
|
|||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 255;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsValuesListForInsert() {
|
||||
return false;
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.dialect;
|
|||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.SybaseConcatFunction;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
|
@ -214,8 +213,6 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
// AVG by default uses the input type, so we possibly need to cast the argument type, hence a special function
|
||||
CommonFunctionFactory.avg_castingNonDoubleArguments( this, queryEngine, SqlAstNodeRenderingMode.DEFAULT );
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "concat", new SybaseConcatFunction( this, queryEngine.getTypeConfiguration() ) );
|
||||
|
||||
//this doesn't work 100% on earlier versions of Sybase
|
||||
//which were missing the third parameter in charindex()
|
||||
//TODO: we could emulate it with substring() like in Postgres
|
||||
|
@ -242,6 +239,11 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
return "select db_name()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdentifierLength() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
if ( to == CastType.STRING ) {
|
||||
|
|
|
@ -22,14 +22,22 @@ import org.hibernate.sql.ast.SqlAstTranslator;
|
|||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
public class DerbyConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
private final Dialect dialect;
|
||||
private final String concatOperator;
|
||||
private final String concatArgumentCastType;
|
||||
private final SqlAstNodeRenderingMode argumentRenderingMode;
|
||||
|
||||
public DerbyConcatFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
|
||||
public CastingConcatFunction(
|
||||
Dialect dialect,
|
||||
String concatOperator,
|
||||
SqlAstNodeRenderingMode argumentRenderingMode,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
super(
|
||||
"concat",
|
||||
StandardArgumentsValidators.min( 1 ),
|
||||
|
@ -38,6 +46,18 @@ public class DerbyConcatFunction extends AbstractSqmSelfRenderingFunctionDescrip
|
|||
)
|
||||
);
|
||||
this.dialect = dialect;
|
||||
this.concatOperator = concatOperator;
|
||||
this.argumentRenderingMode = argumentRenderingMode;
|
||||
this.concatArgumentCastType = dialect.getTypeName(
|
||||
SqlTypes.VARCHAR,
|
||||
dialect.getSizeStrategy().resolveSize(
|
||||
typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( SqlTypes.VARCHAR ),
|
||||
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class ),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,7 +65,7 @@ public class DerbyConcatFunction extends AbstractSqmSelfRenderingFunctionDescrip
|
|||
sqlAppender.appendSql( '(' );
|
||||
renderAsString( sqlAppender, walker, (Expression) sqlAstArguments.get( 0 ) );
|
||||
for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
|
||||
sqlAppender.appendSql( "||" );
|
||||
sqlAppender.appendSql( concatOperator );
|
||||
renderAsString( sqlAppender, walker, (Expression) sqlAstArguments.get( i ) );
|
||||
}
|
||||
sqlAppender.appendSql( ')' );
|
||||
|
@ -55,11 +75,12 @@ public class DerbyConcatFunction extends AbstractSqmSelfRenderingFunctionDescrip
|
|||
final JdbcMapping sourceMapping = expression.getExpressionType().getJdbcMappings().get( 0 );
|
||||
// No need to cast if we already have a string
|
||||
if ( sourceMapping.getCastType() == CastType.STRING ) {
|
||||
translator.render( expression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
translator.render( expression, argumentRenderingMode );
|
||||
}
|
||||
else {
|
||||
final String cast = dialect.castPattern( sourceMapping.getCastType(), CastType.STRING );
|
||||
new PatternRenderer( cast ).render( sqlAppender, Collections.singletonList( expression ), translator );
|
||||
new PatternRenderer( cast.replace( "?2", concatArgumentCastType ), argumentRenderingMode )
|
||||
.render( sqlAppender, Collections.singletonList( expression ), translator );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.JavaObjectType;
|
||||
|
||||
/**
|
||||
* A function to pass through a SQL fragment.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class SqlFunction
|
||||
extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
public SqlFunction() {
|
||||
super(
|
||||
"sql",
|
||||
StandardArgumentsValidators.min( 1 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( JavaObjectType.INSTANCE )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final QueryLiteral<String> sqlFragmentLiteral = (QueryLiteral<String>) arguments.get( 0 );
|
||||
final String sqlFragment = sqlFragmentLiteral.getLiteralValue();
|
||||
if ( arguments.size() != 1 ) {
|
||||
int index = 0;
|
||||
for ( int i = 1; i < arguments.size(); i++ ) {
|
||||
final SqlAstNode argument = arguments.get( i );
|
||||
final int paramIndex = sqlFragment.indexOf( '?', index );
|
||||
if ( paramIndex == -1 ) {
|
||||
throw new IllegalArgumentException( "The SQL function passes an argument at index " + i + " but the fragment contains no placeholder for the argument: " + sqlFragment );
|
||||
}
|
||||
sqlAppender.append( sqlFragment, index, paramIndex );
|
||||
argument.accept( walker );
|
||||
index = paramIndex + 1;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
sqlAppender.appendSql( sqlFragment );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
public class SybaseConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
private final Dialect dialect;
|
||||
|
||||
public SybaseConcatFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
|
||||
super(
|
||||
"concat",
|
||||
StandardArgumentsValidators.min( 1 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant(
|
||||
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
|
||||
)
|
||||
);
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(SqlAppender sqlAppender, List<SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
|
||||
sqlAppender.appendSql( '(' );
|
||||
renderAsString( sqlAppender, walker, (Expression) sqlAstArguments.get( 0 ) );
|
||||
for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
|
||||
sqlAppender.appendSql( '+' );
|
||||
renderAsString( sqlAppender, walker, (Expression) sqlAstArguments.get( i ) );
|
||||
}
|
||||
sqlAppender.appendSql( ')' );
|
||||
}
|
||||
|
||||
private void renderAsString(SqlAppender sqlAppender, SqlAstTranslator<?> translator, Expression expression) {
|
||||
final JdbcMapping sourceMapping = expression.getExpressionType().getJdbcMappings().get( 0 );
|
||||
// No need to cast if we already have a string
|
||||
if ( sourceMapping.getCastType() == CastType.STRING ) {
|
||||
translator.render( expression, SqlAstNodeRenderingMode.DEFAULT );
|
||||
}
|
||||
else {
|
||||
final String cast = dialect.castPattern( sourceMapping.getCastType(), CastType.STRING );
|
||||
new PatternRenderer( cast ).render( sqlAppender, Collections.singletonList( expression ), translator );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class StandardTemporaryTableExporter implements TemporaryTableExporter {
|
||||
private final Dialect dialect;
|
||||
|
||||
public StandardTemporaryTableExporter(Dialect dialect) {
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
protected String getCreateCommand() {
|
||||
return dialect.getTemporaryTableCreateCommand();
|
||||
}
|
||||
|
||||
protected String getCreateOptions() {
|
||||
return dialect.getTemporaryTableCreateOptions();
|
||||
}
|
||||
|
||||
protected String getDropCommand() {
|
||||
return dialect.getTemporaryTableDropCommand();
|
||||
}
|
||||
|
||||
protected String getTruncateTableCommand() {
|
||||
return dialect.getTemporaryTableTruncateCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlCreateCommand(TemporaryTable temporaryTable) {
|
||||
final StringBuilder buffer = new StringBuilder( getCreateCommand() ).append( ' ' );
|
||||
buffer.append( temporaryTable.getQualifiedTableName() );
|
||||
buffer.append( '(' );
|
||||
|
||||
for ( TemporaryTableColumn column : temporaryTable.getColumns() ) {
|
||||
buffer.append( column.getColumnName() ).append( ' ' );
|
||||
final int sqlTypeCode = column.getJdbcMapping().getJdbcTypeDescriptor().getDefaultSqlTypeCode();
|
||||
final String databaseTypeName = column.getSqlTypeDefinition();
|
||||
|
||||
buffer.append( databaseTypeName );
|
||||
|
||||
final String columnAnnotation = dialect.getCreateTemporaryTableColumnAnnotation( sqlTypeCode );
|
||||
if ( !columnAnnotation.isEmpty() ) {
|
||||
buffer.append( ' ' ).append( columnAnnotation );
|
||||
}
|
||||
|
||||
if ( column.isNullable() ) {
|
||||
final String nullColumnString = dialect.getNullColumnString( databaseTypeName );
|
||||
if ( !databaseTypeName.contains( nullColumnString ) ) {
|
||||
buffer.append( nullColumnString );
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffer.append( " not null" );
|
||||
}
|
||||
buffer.append( ", " );
|
||||
}
|
||||
if ( dialect.supportsTemporaryTablePrimaryKey() ) {
|
||||
buffer.append( "primary key (" );
|
||||
for ( TemporaryTableColumn column : temporaryTable.getColumns() ) {
|
||||
if ( column.isPrimaryKey() ) {
|
||||
buffer.append( column.getColumnName() );
|
||||
buffer.append( ", " );
|
||||
}
|
||||
}
|
||||
buffer.setLength( buffer.length() - 2 );
|
||||
buffer.append( ')' );
|
||||
}
|
||||
else {
|
||||
buffer.setLength( buffer.length() - 2 );
|
||||
}
|
||||
buffer.append( ')' );
|
||||
|
||||
final String createOptions = getCreateOptions();
|
||||
if ( createOptions != null ) {
|
||||
buffer.append( ' ' ).append( createOptions );
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlDropCommand(TemporaryTable idTable) {
|
||||
return getDropCommand() + " " + idTable.getQualifiedTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlTruncateCommand(
|
||||
TemporaryTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( idTable.getSessionUidColumn() != null ) {
|
||||
assert sessionUidAccess != null;
|
||||
final String uid = sessionUidAccess.apply( session );
|
||||
return getTruncateTableCommand() + " " + idTable.getQualifiedTableName()
|
||||
+ " where " + idTable.getSessionUidColumn().getColumnName() + " = " + uid;
|
||||
}
|
||||
else {
|
||||
return getTruncateTableCommand() + " " + idTable.getQualifiedTableName();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.relational.Exportable;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Contributable;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class TemporaryTable implements Exportable, Contributable {
|
||||
|
||||
public static final String ID_TABLE_PREFIX = "HT_";
|
||||
public static final String ENTITY_TABLE_PREFIX = "HTE_";
|
||||
public static final String DEFAULT_ALIAS = "temptable_";
|
||||
public static final String ENTITY_TABLE_IDENTITY_COLUMN = "HTE_IDENTITY";
|
||||
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( TemporaryTable.class );
|
||||
|
||||
private final EntityMappingType entityDescriptor;
|
||||
private final String qualifiedTableName;
|
||||
|
||||
private final TemporaryTableSessionUidColumn sessionUidColumn;
|
||||
private final List<TemporaryTableColumn> columns;
|
||||
|
||||
private final Dialect dialect;
|
||||
|
||||
private TemporaryTable(
|
||||
EntityMappingType entityDescriptor,
|
||||
Function<String, String> temporaryTableNameAdjuster,
|
||||
Dialect dialect,
|
||||
Function<TemporaryTable, List<TemporaryTableColumn>> columnInitializer) {
|
||||
this.entityDescriptor = entityDescriptor;
|
||||
|
||||
// The table name might be a sub-query, which is inappropriate for a temporary table name
|
||||
final String originalTableName = entityDescriptor.getEntityPersister().getSynchronizedQuerySpaces()[0];
|
||||
final String name;
|
||||
if ( Identifier.isQuoted( originalTableName ) ) {
|
||||
name = dialect.quote( temporaryTableNameAdjuster.apply( Identifier.unQuote( originalTableName ) ) );
|
||||
}
|
||||
else {
|
||||
name = temporaryTableNameAdjuster.apply( originalTableName );
|
||||
}
|
||||
if ( name.length() > dialect.getMaxIdentifierLength() ) {
|
||||
this.qualifiedTableName = name.substring( 0, dialect.getMaxIdentifierLength() );
|
||||
}
|
||||
else {
|
||||
this.qualifiedTableName = name;
|
||||
}
|
||||
this.dialect = dialect;
|
||||
if ( dialect.getSupportedTemporaryTableKind() == TemporaryTableKind.PERSISTENT ) {
|
||||
final BasicType<UUID> uuidType = entityDescriptor.getEntityPersister()
|
||||
.getFactory()
|
||||
.getTypeConfiguration()
|
||||
.getBasicTypeForJavaType( UUID.class );
|
||||
this.sessionUidColumn = new TemporaryTableSessionUidColumn(
|
||||
this,
|
||||
uuidType,
|
||||
dialect.getTypeName(
|
||||
uuidType.getJdbcTypeDescriptor(),
|
||||
dialect.getSizeStrategy().resolveSize(
|
||||
uuidType.getJdbcTypeDescriptor(),
|
||||
uuidType.getJavaTypeDescriptor(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.sessionUidColumn = null;
|
||||
}
|
||||
final List<TemporaryTableColumn> columns = columnInitializer.apply( this );
|
||||
if ( sessionUidColumn != null ) {
|
||||
columns.add( sessionUidColumn );
|
||||
}
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public static TemporaryTable createIdTable(
|
||||
EntityMappingType entityDescriptor,
|
||||
Function<String, String> temporaryTableNameAdjuster,
|
||||
Dialect dialect,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new TemporaryTable(
|
||||
entityDescriptor,
|
||||
temporaryTableNameAdjuster,
|
||||
dialect,
|
||||
temporaryTable -> {
|
||||
final List<TemporaryTableColumn> columns = new ArrayList<>();
|
||||
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
|
||||
.getEntityBinding( entityDescriptor.getEntityName() );
|
||||
|
||||
final Iterator<Selectable> itr = entityBinding.getKey().getColumnIterator();
|
||||
final Iterator<JdbcMapping> jdbcMappings = entityDescriptor.getIdentifierMapping()
|
||||
.getJdbcMappings()
|
||||
.iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final Column column = (Column) itr.next();
|
||||
final JdbcMapping jdbcMapping = jdbcMappings.next();
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
column.getText( dialect ),
|
||||
jdbcMapping,
|
||||
column.getSqlType( dialect, runtimeModelCreationContext.getMetadata() ),
|
||||
column.isNullable(),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
entityDescriptor.visitSubTypeAttributeMappings(
|
||||
attribute -> {
|
||||
if ( attribute instanceof PluralAttributeMapping ) {
|
||||
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute;
|
||||
|
||||
if ( pluralAttribute.getSeparateCollectionTable() != null ) {
|
||||
// Ensure that the FK target columns are available
|
||||
final ModelPart fkTarget = pluralAttribute.getKeyDescriptor().getTargetPart();
|
||||
if ( !( fkTarget instanceof EntityIdentifierMapping ) ) {
|
||||
final Value value = entityBinding.getSubclassProperty( pluralAttribute.getAttributeName() )
|
||||
.getValue();
|
||||
final Iterator<Selectable> columnIterator = ( (Collection) value ).getKey()
|
||||
.getColumnIterator();
|
||||
fkTarget.forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
final Selectable selectable = columnIterator.next();
|
||||
if ( selectable instanceof Column ) {
|
||||
final Column column = (Column) selectable;
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
selectable.getText( dialect ),
|
||||
selection.getJdbcMapping(),
|
||||
column.getSqlType(
|
||||
dialect,
|
||||
runtimeModelCreationContext.getMetadata()
|
||||
),
|
||||
column.isNullable()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return columns;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static TemporaryTable createEntityTable(
|
||||
EntityMappingType entityDescriptor,
|
||||
Function<String, String> temporaryTableNameAdjuster,
|
||||
Dialect dialect,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new TemporaryTable(
|
||||
entityDescriptor,
|
||||
temporaryTableNameAdjuster,
|
||||
dialect,
|
||||
temporaryTable -> {
|
||||
final List<TemporaryTableColumn> columns = new ArrayList<>();
|
||||
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
|
||||
.getEntityBinding( entityDescriptor.getEntityName() );
|
||||
|
||||
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister()
|
||||
.getIdentifierGenerator();
|
||||
final boolean identityColumn = identifierGenerator instanceof PostInsertIdentifierGenerator;
|
||||
final boolean hasOptimizer;
|
||||
if ( identityColumn ) {
|
||||
hasOptimizer = false;
|
||||
final Iterator<Selectable> itr = entityBinding.getKey().getColumnIterator();
|
||||
final Iterator<JdbcMapping> jdbcMappings = entityDescriptor.getIdentifierMapping()
|
||||
.getJdbcMappings()
|
||||
.iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final Column column = (Column) itr.next();
|
||||
final JdbcMapping jdbcMapping = jdbcMappings.next();
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
ENTITY_TABLE_IDENTITY_COLUMN,
|
||||
jdbcMapping,
|
||||
column.getSqlType( dialect, runtimeModelCreationContext.getMetadata() ) + " " +
|
||||
dialect.getIdentityColumnSupport().getIdentityColumnString( column.getSqlTypeCode( runtimeModelCreationContext.getMetadata() ) ),
|
||||
// Always report as nullable as the identity column string usually includes the not null constraint
|
||||
true, //column.isNullable()
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( identifierGenerator instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
hasOptimizer = optimizer != null && optimizer.getIncrementSize() > 1;
|
||||
}
|
||||
else {
|
||||
hasOptimizer = false;
|
||||
}
|
||||
}
|
||||
final Iterator<Selectable> itr = entityBinding.getKey().getColumnIterator();
|
||||
final Iterator<JdbcMapping> jdbcMappings = entityDescriptor.getIdentifierMapping()
|
||||
.getJdbcMappings()
|
||||
.iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final Column column = (Column) itr.next();
|
||||
final JdbcMapping jdbcMapping = jdbcMappings.next();
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
column.getText( dialect ),
|
||||
jdbcMapping,
|
||||
column.getSqlType( dialect, runtimeModelCreationContext.getMetadata() ),
|
||||
// We have to set the identity column after the root table insert
|
||||
column.isNullable() || identityColumn || hasOptimizer,
|
||||
!identityColumn && !hasOptimizer
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
|
||||
if ( entityBinding.getDiscriminator() != null && !discriminatorMapping.isFormula() ) {
|
||||
final Column discriminator = (Column) entityBinding.getDiscriminator().getColumnIterator().next();
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
discriminator.getText( dialect ),
|
||||
discriminatorMapping.getJdbcMapping(),
|
||||
discriminator.getSqlType( dialect, runtimeModelCreationContext.getMetadata() ),
|
||||
// We have to set the identity column after the root table insert
|
||||
discriminator.isNullable()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Collect all columns for all entity subtype attributes
|
||||
entityDescriptor.visitSubTypeAttributeMappings(
|
||||
attribute -> {
|
||||
if ( !( attribute instanceof PluralAttributeMapping ) ) {
|
||||
final SimpleValue value = (SimpleValue) entityBinding.getSubclassProperty( attribute.getAttributeName() )
|
||||
.getValue();
|
||||
final Iterator<Selectable> columnIterator = value.getConstraintColumnIterator();
|
||||
attribute.forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
final Selectable selectable = columnIterator.next();
|
||||
if ( selectable instanceof Column ) {
|
||||
final Column column = (Column) selectable;
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
selectable.getText( dialect ),
|
||||
selection.getJdbcMapping(),
|
||||
column.getSqlType(
|
||||
dialect,
|
||||
runtimeModelCreationContext.getMetadata()
|
||||
),
|
||||
// Treat regular temporary table columns as nullable for simplicity
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
if ( hasOptimizer ) {
|
||||
// We add a special row number column that we can use to identify and join rows
|
||||
final BasicType<Integer> integerBasicType = entityDescriptor.getEntityPersister()
|
||||
.getFactory()
|
||||
.getTypeConfiguration()
|
||||
.getBasicTypeForJavaType( Integer.class );
|
||||
final String rowNumberType;
|
||||
if ( dialect.supportsWindowFunctions() ) {
|
||||
rowNumberType = dialect.getTypeName(
|
||||
integerBasicType.getJdbcTypeDescriptor().getJdbcTypeCode(),
|
||||
dialect.getSizeStrategy().resolveSize(
|
||||
integerBasicType.getJdbcTypeDescriptor(),
|
||||
integerBasicType.getJavaTypeDescriptor(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ( dialect.getIdentityColumnSupport().supportsIdentityColumns() ) {
|
||||
rowNumberType = dialect.getTypeName(
|
||||
integerBasicType.getJdbcTypeDescriptor().getJdbcTypeCode(),
|
||||
dialect.getSizeStrategy().resolveSize(
|
||||
integerBasicType.getJdbcTypeDescriptor(),
|
||||
integerBasicType.getJavaTypeDescriptor(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
) + " " +
|
||||
dialect.getIdentityColumnSupport().getIdentityColumnString( integerBasicType.getJdbcTypeDescriptor().getJdbcTypeCode() );
|
||||
}
|
||||
else {
|
||||
LOG.multiTableInsertNotAvailable( entityBinding.getEntityName() );
|
||||
rowNumberType = dialect.getTypeName(
|
||||
integerBasicType.getJdbcTypeDescriptor().getJdbcTypeCode(),
|
||||
dialect.getSizeStrategy().resolveSize(
|
||||
integerBasicType.getJdbcTypeDescriptor(),
|
||||
integerBasicType.getJavaTypeDescriptor(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
columns.add(
|
||||
new TemporaryTableColumn(
|
||||
temporaryTable,
|
||||
"rn_",
|
||||
integerBasicType,
|
||||
rowNumberType,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public EntityMappingType getEntityDescriptor() {
|
||||
return entityDescriptor;
|
||||
}
|
||||
|
||||
public String getQualifiedTableName() {
|
||||
return qualifiedTableName;
|
||||
}
|
||||
|
||||
public List<TemporaryTableColumn> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public TemporaryTableSessionUidColumn getSessionUidColumn() {
|
||||
return sessionUidColumn;
|
||||
}
|
||||
|
||||
public String getTableExpression() {
|
||||
return qualifiedTableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContributor() {
|
||||
return entityDescriptor.getContributor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return getQualifiedTableName();
|
||||
}
|
||||
|
||||
public Dialect getDialect() {
|
||||
return this.dialect;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
|
||||
|
@ -14,24 +14,39 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdTableColumn {
|
||||
private final IdTable containingTable;
|
||||
public class TemporaryTableColumn {
|
||||
private final TemporaryTable containingTable;
|
||||
private final String columnName;
|
||||
private final JdbcMapping jdbcMapping;
|
||||
private final String sqlTypeName;
|
||||
private final boolean nullable;
|
||||
private final boolean primaryKey;
|
||||
|
||||
public IdTableColumn(
|
||||
IdTable containingTable,
|
||||
public TemporaryTableColumn(
|
||||
TemporaryTable containingTable,
|
||||
String columnName,
|
||||
JdbcMapping jdbcMapping,
|
||||
String sqlTypeName) {
|
||||
String sqlTypeName,
|
||||
boolean nullable) {
|
||||
this( containingTable, columnName, jdbcMapping, sqlTypeName, nullable, false );
|
||||
}
|
||||
|
||||
public TemporaryTableColumn(
|
||||
TemporaryTable containingTable,
|
||||
String columnName,
|
||||
JdbcMapping jdbcMapping,
|
||||
String sqlTypeName,
|
||||
boolean nullable,
|
||||
boolean primaryKey) {
|
||||
this.containingTable = containingTable;
|
||||
this.columnName = columnName;
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
this.sqlTypeName = sqlTypeName;
|
||||
this.nullable = nullable;
|
||||
this.primaryKey = primaryKey;
|
||||
}
|
||||
|
||||
public IdTable getContainingTable() {
|
||||
public TemporaryTable getContainingTable() {
|
||||
return containingTable;
|
||||
}
|
||||
|
||||
|
@ -50,4 +65,12 @@ public class IdTableColumn {
|
|||
public String getSqlTypeDefinition() {
|
||||
return sqlTypeName;
|
||||
}
|
||||
|
||||
public boolean isNullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public boolean isPrimaryKey() {
|
||||
return primaryKey;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
|
@ -13,13 +13,13 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IdTableExporter {
|
||||
String getSqlCreateCommand(IdTable idTable);
|
||||
public interface TemporaryTableExporter {
|
||||
String getSqlCreateCommand(TemporaryTable idTable);
|
||||
|
||||
String getSqlDropCommand(IdTable idTable);
|
||||
String getSqlDropCommand(TemporaryTable idTable);
|
||||
|
||||
String getSqlTruncateCommand(
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
SharedSessionContractImplementor session);
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -27,24 +27,34 @@ import org.hibernate.jdbc.AbstractWork;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class IdTableHelper {
|
||||
private final static CoreMessageLogger log = CoreLogging.messageLogger( IdTableHelper.class );
|
||||
public class TemporaryTableHelper {
|
||||
private final static CoreMessageLogger log = CoreLogging.messageLogger( TemporaryTableHelper.class );
|
||||
|
||||
public static final String SESSION_ID_COLUMN_NAME = "hib_sess_id";
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Creation
|
||||
|
||||
public static class IdTableCreationWork extends AbstractWork {
|
||||
private final IdTable idTable;
|
||||
private final IdTableExporter exporter;
|
||||
public static class TemporaryTableCreationWork extends AbstractWork {
|
||||
private final TemporaryTable temporaryTable;
|
||||
private final TemporaryTableExporter exporter;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
public IdTableCreationWork(
|
||||
IdTable idTable,
|
||||
IdTableExporter exporter,
|
||||
public TemporaryTableCreationWork(
|
||||
TemporaryTable temporaryTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.idTable = idTable;
|
||||
this(
|
||||
temporaryTable,
|
||||
sessionFactory.getJdbcServices().getDialect().getTemporaryTableExporter(),
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
public TemporaryTableCreationWork(
|
||||
TemporaryTable temporaryTable,
|
||||
TemporaryTableExporter exporter,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.temporaryTable = temporaryTable;
|
||||
this.exporter = exporter;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
@ -54,7 +64,7 @@ public class IdTableHelper {
|
|||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
|
||||
try {
|
||||
final String creationCommand = exporter.getSqlCreateCommand( idTable );
|
||||
final String creationCommand = exporter.getSqlCreateCommand( temporaryTable );
|
||||
logStatement( creationCommand, jdbcServices );
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
|
@ -63,15 +73,15 @@ public class IdTableHelper {
|
|||
}
|
||||
catch (SQLException e) {
|
||||
log.debugf(
|
||||
"unable to create id table [%s]; `%s` failed : %s",
|
||||
idTable.getQualifiedTableName(),
|
||||
"unable to create temporary table [%s]; `%s` failed : %s",
|
||||
temporaryTable.getQualifiedTableName(),
|
||||
creationCommand,
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
log.debugf( "Error creating id table(s) : %s", e.getMessage() );
|
||||
log.debugf( "Error creating temporary table(s) : %s", e.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,16 +90,26 @@ public class IdTableHelper {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Drop
|
||||
|
||||
public static class IdTableDropWork extends AbstractWork {
|
||||
private final IdTable idTable;
|
||||
private final IdTableExporter exporter;
|
||||
public static class TemporaryTableDropWork extends AbstractWork {
|
||||
private final TemporaryTable temporaryTable;
|
||||
private final TemporaryTableExporter exporter;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
IdTableDropWork(
|
||||
IdTable idTable,
|
||||
IdTableExporter exporter,
|
||||
public TemporaryTableDropWork(
|
||||
TemporaryTable temporaryTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.idTable = idTable;
|
||||
this(
|
||||
temporaryTable,
|
||||
sessionFactory.getJdbcServices().getDialect().getTemporaryTableExporter(),
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
public TemporaryTableDropWork(
|
||||
TemporaryTable temporaryTable,
|
||||
TemporaryTableExporter exporter,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.temporaryTable = temporaryTable;
|
||||
this.exporter = exporter;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
@ -99,7 +119,7 @@ public class IdTableHelper {
|
|||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
|
||||
try {
|
||||
final String dropCommand = exporter.getSqlDropCommand( idTable );
|
||||
final String dropCommand = exporter.getSqlDropCommand( temporaryTable );
|
||||
logStatement( dropCommand, jdbcServices );
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
|
@ -108,15 +128,15 @@ public class IdTableHelper {
|
|||
}
|
||||
catch (SQLException e) {
|
||||
log.debugf(
|
||||
"unable to drop id table [%s]; `%s` failed : %s",
|
||||
idTable.getQualifiedTableName(),
|
||||
"unable to drop temporary table [%s]; `%s` failed : %s",
|
||||
temporaryTable.getQualifiedTableName(),
|
||||
dropCommand,
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
log.debugf( "Error dropping id table(s) : %s", e.getMessage() );
|
||||
log.debugf( "Error dropping temporary table(s) : %s", e.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,18 +145,18 @@ public class IdTableHelper {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Clean
|
||||
|
||||
public static void cleanIdTableRows(
|
||||
IdTable idTable,
|
||||
IdTableExporter exporter,
|
||||
public static void cleanTemporaryTableRows(
|
||||
TemporaryTable temporaryTable,
|
||||
TemporaryTableExporter exporter,
|
||||
Function<SharedSessionContractImplementor,String> sessionUidAccess,
|
||||
SharedSessionContractImplementor session) {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
final String sql = exporter.getSqlTruncateCommand( idTable, sessionUidAccess, session );
|
||||
final String sql = exporter.getSqlTruncateCommand( temporaryTable, sessionUidAccess, session );
|
||||
|
||||
ps = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||
|
||||
if ( idTable.getSessionUidColumn() != null ) {
|
||||
if ( temporaryTable.getSessionUidColumn() != null ) {
|
||||
final String sessionUid = sessionUidAccess.apply( session );
|
||||
ps.setString( 1, sessionUid );
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public enum TemporaryTableKind {
|
||||
PERSISTENT,
|
||||
LOCAL,
|
||||
GLOBAL;
|
||||
}
|
|
@ -4,23 +4,25 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.dialect.temptable;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdTableSessionUidColumn extends IdTableColumn {
|
||||
public IdTableSessionUidColumn(
|
||||
IdTable containingTable,
|
||||
public class TemporaryTableSessionUidColumn extends TemporaryTableColumn {
|
||||
public TemporaryTableSessionUidColumn(
|
||||
TemporaryTable containingTable,
|
||||
JdbcMapping jdbcMapping,
|
||||
String sqlTypeName) {
|
||||
super(
|
||||
containingTable,
|
||||
IdTableHelper.SESSION_ID_COLUMN_NAME,
|
||||
TemporaryTableHelper.SESSION_ID_COLUMN_NAME,
|
||||
jdbcMapping,
|
||||
sqlTypeName
|
||||
sqlTypeName,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
|
@ -73,6 +73,11 @@ public class IdentityGenerator extends AbstractPostInsertGenerator {
|
|||
return insert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prepareIdentifierGeneratingInsert(String insertSQL) {
|
||||
return dialect.getIdentityColumnSupport().appendIdentitySelectToInsert( insertSQL );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreparedStatement prepare(String insertSQL, SharedSessionContractImplementor session) throws SQLException {
|
||||
return session
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.engine.spi.SessionEventListenerManager;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.enhanced.AccessCallback;
|
||||
import org.hibernate.id.enhanced.LegacyHiLoAlgorithmOptimizer;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
|
@ -112,6 +113,12 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
|
|||
private Class returnClass;
|
||||
private int keySize;
|
||||
|
||||
@Override
|
||||
public Optimizer getOptimizer() {
|
||||
return hiloOptimizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object generate(final SharedSessionContractImplementor session, Object obj) {
|
||||
DeprecationLogger.DEPRECATION_LOGGER.deprecatedTableGenerator( getClass().getName() );
|
||||
|
||||
|
|
|
@ -46,4 +46,6 @@ public interface OptimizableGenerator extends IdentifierGenerator, ExportablePro
|
|||
* NOTE : has precedence over {@link #INCREMENT_PARAM}
|
||||
*/
|
||||
String OPT_PARAM = "optimizer";
|
||||
|
||||
Optimizer getOptimizer();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.boot.model.relational.Sequence;
|
|||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
|
@ -87,7 +88,11 @@ public class SequenceGenerator
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
public Optimizer getOptimizer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
|
||||
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSequenceGenerator( getClass().getName() );
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.hibernate.MappingException;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.enhanced.AccessCallback;
|
||||
import org.hibernate.id.enhanced.LegacyHiLoAlgorithmOptimizer;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -37,6 +38,11 @@ public class SequenceHiLoGenerator extends SequenceGenerator {
|
|||
|
||||
private LegacyHiLoAlgorithmOptimizer hiloOptimizer;
|
||||
|
||||
@Override
|
||||
public Optimizer getOptimizer() {
|
||||
return hiloOptimizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
|
||||
super.configure( type, params, serviceRegistry );
|
||||
|
|
|
@ -165,6 +165,7 @@ public class SequenceStyleGenerator
|
|||
*
|
||||
* @return Value for property 'optimizer'.
|
||||
*/
|
||||
@Override
|
||||
public Optimizer getOptimizer() {
|
||||
return optimizer;
|
||||
}
|
||||
|
@ -545,11 +546,8 @@ public class SequenceStyleGenerator
|
|||
|
||||
@Override
|
||||
public boolean supportsBulkInsertionIdentifierGeneration() {
|
||||
// it does, as long as
|
||||
// 1) there is no (non-noop) optimizer in use
|
||||
// 2) the underlying structure is a sequence
|
||||
return NoopOptimizer.class.isInstance( getOptimizer() )
|
||||
&& getDatabaseStructure().isPhysicalSequence();
|
||||
// it does, as long as the underlying structure is a sequence
|
||||
return getDatabaseStructure().isPhysicalSequence();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -310,6 +310,7 @@ public class TableGenerator implements PersistentIdentifierGenerator {
|
|||
*
|
||||
* @return Out optimizer.
|
||||
*/
|
||||
@Override
|
||||
public final Optimizer getOptimizer() {
|
||||
return optimizer;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,16 @@ public interface InsertGeneratedIdentifierDelegate {
|
|||
*/
|
||||
IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context);
|
||||
|
||||
/**
|
||||
* Append SQL specific to the delegate's mode
|
||||
* of handling generated key values.
|
||||
*
|
||||
* @return The insert SQL.
|
||||
*/
|
||||
default String prepareIdentifierGeneratingInsert(String insertSQL) {
|
||||
return insertSQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the indicated insert SQL statement and determine the identifier value
|
||||
* generated.
|
||||
|
|
|
@ -1825,4 +1825,8 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
@Message(value = "The Javassist based BytecodeProvider has been removed: remove the `hibernate.bytecode.provider` configuration property to switch to the default provider", id = 508)
|
||||
HibernateException usingRemovedJavassistBytecodeProvider();
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "Multi-table insert is not available due to missing identity and window function support for: %s", id = 509)
|
||||
void multiTableInsertNotAvailable(String entityName);
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.internal;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -208,11 +209,28 @@ public class FilterHelper {
|
|||
if ( ! (parameterType instanceof JdbcMapping ) ) {
|
||||
throw new MappingException( String.format( "parameter [%s] for filter [%s] is not of JdbcMapping type", parameterName, filterName ) );
|
||||
}
|
||||
final JdbcMapping jdbcMapping = (JdbcMapping) parameterType;
|
||||
final Object parameterValue = enabledFilter.getParameter( parameterName );
|
||||
if ( parameterValue == null ) {
|
||||
throw new MappingException( String.format( "unknown parameter [%s] for filter [%s]", parameterName, filterName ) );
|
||||
}
|
||||
parameters.add( new FilterJdbcParameter( (JdbcMapping) parameterType, parameterValue ) );
|
||||
if ( parameterValue instanceof Iterable && !jdbcMapping.getJavaTypeDescriptor().isInstance( parameterValue ) ) {
|
||||
final Iterator<?> iterator = ( (Iterable<?>) parameterValue ).iterator();
|
||||
if ( iterator.hasNext() ) {
|
||||
parameters.add( new FilterJdbcParameter( jdbcMapping, iterator.next() ) );
|
||||
while ( iterator.hasNext() ) {
|
||||
sb.append( ",?" );
|
||||
parameters.add( new FilterJdbcParameter( jdbcMapping, iterator.next() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need a dummy value if the list is empty
|
||||
parameters.add( new FilterJdbcParameter( jdbcMapping, null ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
parameters.add( new FilterJdbcParameter( jdbcMapping, parameterValue ) );
|
||||
}
|
||||
}
|
||||
sb.append( filterFragment, pos, filterFragment.length() );
|
||||
return new FilterPredicate( sb.toString(), parameters );
|
||||
|
|
|
@ -857,6 +857,12 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
jdbcConnectionAccess
|
||||
);
|
||||
}
|
||||
if ( entityPersister.getSqmMultiTableInsertStrategy() != null ) {
|
||||
entityPersister.getSqmMultiTableInsertStrategy().release(
|
||||
this,
|
||||
jdbcConnectionAccess
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
( (MappingMetamodelImpl) runtimeMetamodels.getMappingMetamodel() ).close();
|
||||
|
|
|
@ -109,6 +109,12 @@ public class OneToOne extends ToOne {
|
|||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Selectable> getConstraintColumnIterator() {
|
||||
return identifier.getColumnIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constrained.
|
||||
* @return boolean
|
||||
|
|
|
@ -217,6 +217,10 @@ public abstract class SimpleValue implements KeyValue {
|
|||
return columns;
|
||||
}
|
||||
|
||||
public Iterator<Selectable> getConstraintColumnIterator() {
|
||||
return getColumnIterator();
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.FetchableContainer;
|
||||
|
||||
|
@ -19,7 +20,7 @@ import org.hibernate.sql.results.graph.FetchableContainer;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer {
|
||||
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer, TableGroupJoinProducer {
|
||||
BasicValuedModelPart getDiscriminatorPart();
|
||||
BasicValuedModelPart getKeyPart();
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue
|
|||
|
||||
String getConcreteEntityNameForDiscriminatorValue(Object value);
|
||||
|
||||
boolean isPhysical();
|
||||
|
||||
/**
|
||||
* Create the appropriate SQL expression for this discriminator
|
||||
*
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.metamodel.UnsupportedMappingException;
|
|||
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
|
@ -232,6 +233,10 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
|
|||
return getEntityPersister().getSqmMultiTableMutationStrategy();
|
||||
}
|
||||
|
||||
default SqmMultiTableInsertStrategy getSqmMultiTableInsertStrategy() {
|
||||
return getEntityPersister().getSqmMultiTableInsertStrategy();
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Special model parts - identifier, discriminator, etc
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
|
|||
/**
|
||||
* Descriptor for foreign-keys
|
||||
*/
|
||||
public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||
public interface ForeignKeyDescriptor extends VirtualModelPart, ValueMapping {
|
||||
|
||||
enum Nature {
|
||||
KEY,
|
||||
|
|
|
@ -78,6 +78,11 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPhysical() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicFetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
|
|
|
@ -61,7 +61,7 @@ import org.hibernate.type.descriptor.java.MutabilityPlan;
|
|||
*/
|
||||
public class DiscriminatedAssociationAttributeMapping
|
||||
extends AbstractSingularAttributeMapping
|
||||
implements DiscriminatedAssociationModelPart, TableGroupJoinProducer {
|
||||
implements DiscriminatedAssociationModelPart {
|
||||
private final NavigableRole navigableRole;
|
||||
private final DiscriminatedAssociationMapping discriminatorMapping;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
|
|
@ -22,7 +22,15 @@ import org.hibernate.metamodel.mapping.ModelPart;
|
|||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.from.StandardVirtualTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
|
@ -190,4 +198,62 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode
|
|||
int span = getDiscriminatorPart().forEachJdbcType( offset, action );
|
||||
return span + getKeyPart().forEachJdbcType( offset + span, action );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroupJoin createTableGroupJoin(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup lhs,
|
||||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean addsPredicate,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
FromClauseAccess fromClauseAccess,
|
||||
SqlAstCreationContext creationContext) {
|
||||
final TableGroup tableGroup = createRootTableGroupJoin(
|
||||
navigablePath,
|
||||
lhs,
|
||||
explicitSourceAlias,
|
||||
sqlAstJoinType,
|
||||
fetched,
|
||||
null,
|
||||
aliasBaseGenerator,
|
||||
sqlExpressionResolver,
|
||||
fromClauseAccess,
|
||||
creationContext
|
||||
);
|
||||
|
||||
return new TableGroupJoin( navigablePath, sqlAstJoinType, tableGroup );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroup createRootTableGroupJoin(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup lhs,
|
||||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
Consumer<Predicate> predicateConsumer,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
FromClauseAccess fromClauseAccess,
|
||||
SqlAstCreationContext creationContext) {
|
||||
return new StandardVirtualTableGroup(
|
||||
navigablePath,
|
||||
this,
|
||||
lhs,
|
||||
fetched
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
||||
return SqlAstJoinType.LEFT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlAliasStem() {
|
||||
return collectionDescriptor.getAttributeMapping().getSqlAliasStem();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -444,6 +444,11 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
return associationKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getMappedType() {
|
||||
return getPartMappingType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return targetSide.getModelPart().getPartMappingType();
|
||||
|
|
|
@ -27,6 +27,7 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato
|
|||
private final String tableExpression;
|
||||
private final String columnName;
|
||||
private final String columnFormula;
|
||||
private final boolean isPhysical;
|
||||
|
||||
public ExplicitColumnDiscriminatorMappingImpl(
|
||||
EntityPersister entityDescriptor,
|
||||
|
@ -34,9 +35,11 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato
|
|||
String tableExpression,
|
||||
String columnExpression,
|
||||
boolean isFormula,
|
||||
boolean isPhysical,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
super( discriminatorType.getJdbcMapping(), entityDescriptor, discriminatorType, creationProcess );
|
||||
this.tableExpression = tableExpression;
|
||||
this.isPhysical = isPhysical;
|
||||
if ( isFormula ) {
|
||||
columnName = null;
|
||||
columnFormula = columnExpression;
|
||||
|
@ -95,4 +98,9 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato
|
|||
public boolean isFormula() {
|
||||
return columnFormula != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPhysical() {
|
||||
return isPhysical;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
|||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.from.CorrelatedTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.MappedByTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.PluralTableGroup;
|
||||
|
@ -1349,8 +1350,6 @@ public class ToOneAttributeMapping
|
|||
)
|
||||
);
|
||||
|
||||
initializeIfNeeded( lhs, sqlAstJoinType, lazyTableGroup );
|
||||
|
||||
return join;
|
||||
}
|
||||
|
||||
|
@ -1368,6 +1367,21 @@ public class ToOneAttributeMapping
|
|||
SqlAstCreationContext creationContext) {
|
||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( sqlAliasStem );
|
||||
final boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable;
|
||||
|
||||
TableGroup realParentTableGroup = lhs;
|
||||
while ( realParentTableGroup.getModelPart() instanceof EmbeddableValuedModelPart ) {
|
||||
realParentTableGroup = fromClauseAccess.findTableGroup( realParentTableGroup.getNavigablePath().getParent() );
|
||||
}
|
||||
final TableGroupProducer tableGroupProducer;
|
||||
if ( realParentTableGroup instanceof CorrelatedTableGroup ) {
|
||||
// If the parent is a correlated table group, we can't refer to columns of the table in the outer query,
|
||||
// because the context in which a column is used could be an aggregate function.
|
||||
// Using a parent column in such a case would lead to an error if the parent query lacks a proper group by
|
||||
tableGroupProducer = entityMappingType;
|
||||
}
|
||||
else {
|
||||
tableGroupProducer = this;
|
||||
}
|
||||
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
|
||||
canUseInnerJoin,
|
||||
navigablePath,
|
||||
|
@ -1402,7 +1416,7 @@ public class ToOneAttributeMapping
|
|||
&& targetKeyPropertyNames.contains( sb.toString() )
|
||||
&& identifyingColumnsTableExpression.equals( tableExpression );
|
||||
},
|
||||
this,
|
||||
tableGroupProducer,
|
||||
explicitSourceAlias,
|
||||
sqlAliasBase,
|
||||
creationContext.getSessionFactory(),
|
||||
|
@ -1426,7 +1440,13 @@ public class ToOneAttributeMapping
|
|||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( realParentTableGroup instanceof CorrelatedTableGroup ) {
|
||||
// Force initialization of the underlying table group join to retain cardinality
|
||||
lazyTableGroup.getPrimaryTableReference();
|
||||
}
|
||||
else {
|
||||
initializeIfNeeded( lhs, sqlAstJoinType, lazyTableGroup );
|
||||
}
|
||||
|
||||
|
|
|
@ -55,10 +55,7 @@ public class VirtualIdRepresentationStrategy implements EmbeddableRepresentation
|
|||
|
||||
@Override
|
||||
public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) {
|
||||
return PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess(
|
||||
entityMappingType.getMappedJavaTypeDescriptor().getJavaTypeClass(),
|
||||
bootAttributeDescriptor.getName()
|
||||
);
|
||||
return entityMappingType.getRepresentationStrategy().resolvePropertyAccess( bootAttributeDescriptor );
|
||||
}
|
||||
|
||||
private static class InstantiatorAdapter implements StandardEmbeddableInstantiator {
|
||||
|
|
|
@ -6,15 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.query.NullPrecedence;
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SortSpecification;
|
||||
|
@ -27,28 +23,10 @@ import org.hibernate.sql.ast.tree.select.SortSpecification;
|
|||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class SelfRenderingOrderingExpression implements OrderingExpression, SelfRenderingExpression {
|
||||
private final String expression;
|
||||
public class SelfRenderingOrderingExpression extends SelfRenderingSqlFragmentExpression implements OrderingExpression {
|
||||
|
||||
public SelfRenderingOrderingExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMappingContainer getExpressionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderToSql(
|
||||
SqlAppender sqlAppender,
|
||||
SqlAstTranslator<?> walker,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
sqlAppender.append( expression );
|
||||
super( expression );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -99,9 +99,12 @@ import org.hibernate.engine.spi.ValueInclusion;
|
|||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.LoadEvent;
|
||||
import org.hibernate.id.Assigned;
|
||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.id.insert.Binder;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
|
@ -201,6 +204,7 @@ import org.hibernate.query.named.NamedQueryMemento;
|
|||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sql.internal.SQLQueryParser;
|
||||
import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.Alias;
|
||||
import org.hibernate.sql.Delete;
|
||||
|
@ -285,6 +289,7 @@ public abstract class AbstractEntityPersister
|
|||
private MultiNaturalIdLoader<?> multiNaturalIdLoader;
|
||||
|
||||
private SqmMultiTableMutationStrategy sqmMultiTableMutationStrategy;
|
||||
private SqmMultiTableInsertStrategy sqmMultiTableInsertStrategy;
|
||||
|
||||
private final NavigableRole navigableRole;
|
||||
|
||||
|
@ -5561,7 +5566,8 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
);
|
||||
|
||||
if ( isMultiTable() ) {
|
||||
boolean needsMultiTableInsert;
|
||||
if ( needsMultiTableInsert = isMultiTable() ) {
|
||||
creationProcess.registerInitializationCallback(
|
||||
"Entity(" + getEntityName() + ") `sqmMultiTableMutationStrategy` interpretation",
|
||||
() -> {
|
||||
|
@ -5591,6 +5597,44 @@ public abstract class AbstractEntityPersister
|
|||
else {
|
||||
sqmMultiTableMutationStrategy = null;
|
||||
}
|
||||
|
||||
if ( !needsMultiTableInsert && getIdentifierGenerator() instanceof BulkInsertionCapableIdentifierGenerator ) {
|
||||
if ( getIdentifierGenerator() instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) getIdentifierGenerator() ).getOptimizer();
|
||||
needsMultiTableInsert = optimizer != null && optimizer.getIncrementSize() > 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( needsMultiTableInsert ) {
|
||||
creationProcess.registerInitializationCallback(
|
||||
"Entity(" + getEntityName() + ") `sqmMultiTableInsertStrategy` interpretation",
|
||||
() -> {
|
||||
try {
|
||||
sqmMultiTableInsertStrategy = interpretSqmMultiTableInsertStrategy(
|
||||
this,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
if ( sqmMultiTableInsertStrategy == null ) {
|
||||
return false;
|
||||
}
|
||||
sqmMultiTableInsertStrategy.prepare(
|
||||
creationProcess,
|
||||
creationContext.getSessionFactory()
|
||||
.getJdbcServices()
|
||||
.getBootstrapJdbcConnectionAccess()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
sqmMultiTableInsertStrategy = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareMappingModel(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) {
|
||||
|
@ -5709,7 +5753,21 @@ public abstract class AbstractEntityPersister
|
|||
entityMappingDescriptor,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
protected static SqmMultiTableInsertStrategy interpretSqmMultiTableInsertStrategy(
|
||||
AbstractEntityPersister entityMappingDescriptor,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
// we need the boot model so we can have access to the Table
|
||||
final RootClass entityBootDescriptor = (RootClass) creationProcess.getCreationContext()
|
||||
.getBootModel()
|
||||
.getEntityBinding( entityMappingDescriptor.getRootEntityName() );
|
||||
|
||||
return SqmMutationStrategyHelper.resolveInsertStrategy(
|
||||
entityBootDescriptor,
|
||||
entityMappingDescriptor,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5717,6 +5775,10 @@ public abstract class AbstractEntityPersister
|
|||
return sqmMultiTableMutationStrategy;
|
||||
}
|
||||
|
||||
public SqmMultiTableInsertStrategy getSqmMultiTableInsertStrategy() {
|
||||
return sqmMultiTableInsertStrategy;
|
||||
}
|
||||
|
||||
protected int getStateArrayInitialPosition(MappingModelCreationProcess creationProcess) {
|
||||
// todo (6.0) not sure this is correct in case of SingleTable Inheritance and for Table per class when the selection is the root
|
||||
int stateArrayPosition;
|
||||
|
@ -5730,6 +5792,10 @@ public abstract class AbstractEntityPersister
|
|||
return stateArrayPosition;
|
||||
}
|
||||
|
||||
protected boolean isPhysicalDiscriminator() {
|
||||
return getDiscriminatorFormulaTemplate() == null;
|
||||
}
|
||||
|
||||
protected EntityDiscriminatorMapping generateDiscriminatorMapping(MappingModelCreationProcess modelCreationProcess) {
|
||||
if ( getDiscriminatorType() == null) {
|
||||
return null;
|
||||
|
@ -5748,6 +5814,7 @@ public abstract class AbstractEntityPersister
|
|||
getTableName(),
|
||||
discriminatorColumnExpression,
|
||||
getDiscriminatorFormulaTemplate() != null,
|
||||
isPhysicalDiscriminator(),
|
||||
modelCreationProcess
|
||||
);
|
||||
}
|
||||
|
@ -6236,6 +6303,13 @@ public abstract class AbstractEntityPersister
|
|||
if ( superMappingType != null ) {
|
||||
final ModelPart superDefinedAttribute = superMappingType.findSubPart( name, superMappingType );
|
||||
if ( superDefinedAttribute != null ) {
|
||||
// Prefer the identifier mapping of the concrete class
|
||||
if ( superDefinedAttribute instanceof EntityIdentifierMapping ) {
|
||||
final ModelPart identifierModelPart = getIdentifierModelPart( name, treatTargetType );
|
||||
if ( identifierModelPart != null ) {
|
||||
return identifierModelPart;
|
||||
}
|
||||
}
|
||||
return superDefinedAttribute;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
||||
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
|
||||
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
|
||||
|
@ -158,6 +159,10 @@ public interface EntityPersister
|
|||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
default SqmMultiTableInsertStrategy getSqmMultiTableInsertStrategy() {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the underlying entity metamodel instance...
|
||||
*
|
||||
|
|
|
@ -1213,6 +1213,11 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPhysicalDiscriminator() {
|
||||
return explicitDiscriminatorColumnName != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityDiscriminatorMapping generateDiscriminatorMapping(MappingModelCreationProcess modelCreationProcess) {
|
||||
EntityMappingType superMappingType = getSuperMappingType();
|
||||
|
|
|
@ -419,6 +419,11 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPhysicalDiscriminator() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityDiscriminatorMapping generateDiscriminatorMapping(MappingModelCreationProcess modelCreationProcess) {
|
||||
if ( hasSubclasses() ) {
|
||||
|
|
|
@ -338,7 +338,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
final ParseTree parseTree = ctx.getChild( 0 );
|
||||
if ( parseTree instanceof HqlParser.SelectStatementContext ) {
|
||||
final SqmSelectStatement<R> selectStatement = visitSelectStatement( (HqlParser.SelectStatementContext) parseTree );
|
||||
selectStatement.getQueryPart().validateFetchStructureAndOwners();
|
||||
selectStatement.getQueryPart().validateQueryStructureAndFetchOwners();
|
||||
return selectStatement;
|
||||
}
|
||||
else if ( parseTree instanceof HqlParser.InsertStatementContext ) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Map;
|
|||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
|
||||
|
@ -60,4 +61,10 @@ public interface QueryEngineOptions {
|
|||
* target of the mutation is a multi-table entity.
|
||||
*/
|
||||
SqmMultiTableMutationStrategy getCustomSqmMultiTableMutationStrategy();
|
||||
|
||||
/**
|
||||
* Contract for handling SQM trees representing insertion (INSERT) queries where the
|
||||
* target of the mutation is a multi-table entity.
|
||||
*/
|
||||
SqmMultiTableInsertStrategy getCustomSqmMultiTableInsertStrategy();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class MultiTableInsertQueryPlan implements NonSelectQueryPlan {
|
||||
private final SqmInsertStatement<?> sqmInsert;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
private final SqmMultiTableInsertStrategy mutationStrategy;
|
||||
|
||||
public MultiTableInsertQueryPlan(
|
||||
SqmInsertStatement<?> sqmInsert,
|
||||
DomainParameterXref domainParameterXref,
|
||||
SqmMultiTableInsertStrategy mutationStrategy) {
|
||||
this.sqmInsert = sqmInsert;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
this.mutationStrategy = mutationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmInsert );
|
||||
return mutationStrategy.executeInsert( sqmInsert, domainParameterXref, executionContext );
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.query.QueryTypeMismatchException;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
|
||||
import org.hibernate.query.hql.internal.QuerySplitter;
|
||||
import org.hibernate.query.hql.spi.HqlQueryImplementor;
|
||||
|
@ -59,15 +60,21 @@ import org.hibernate.query.spi.ScrollableResultsImplementor;
|
|||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmValues;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQueryGroup;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
|
||||
|
@ -142,6 +149,9 @@ public class QuerySqmImpl<R>
|
|||
else if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
|
||||
verifyImmutableEntityUpdate( hqlString, (SqmUpdateStatement<R>) sqmStatement, producer.getFactory() );
|
||||
}
|
||||
else if ( sqmStatement instanceof SqmInsertStatement<?> ) {
|
||||
verifyInsertTypesMatch( hqlString, (SqmInsertStatement<R>) sqmStatement );
|
||||
}
|
||||
this.resultType = resultType;
|
||||
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
|
||||
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
|
||||
|
@ -203,6 +213,9 @@ public class QuerySqmImpl<R>
|
|||
else if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
|
||||
verifyImmutableEntityUpdate( hqlString, (SqmUpdateStatement<R>) sqmStatement, producer.getFactory() );
|
||||
}
|
||||
else if ( sqmStatement instanceof SqmInsertStatement<?> ) {
|
||||
verifyInsertTypesMatch( hqlString, (SqmInsertStatement<R>) sqmStatement );
|
||||
}
|
||||
|
||||
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
|
||||
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
|
||||
|
@ -227,7 +240,7 @@ public class QuerySqmImpl<R>
|
|||
SqmUtil.verifyIsSelectStatement( sqmStatement, null );
|
||||
final SqmQueryPart<R> queryPart = ( (SqmSelectStatement<R>) sqmStatement ).getQueryPart();
|
||||
// For criteria queries, we have to validate the fetch structure here
|
||||
queryPart.validateFetchStructureAndOwners();
|
||||
queryPart.validateQueryStructureAndFetchOwners();
|
||||
visitQueryReturnType(
|
||||
queryPart,
|
||||
resultType,
|
||||
|
@ -241,6 +254,9 @@ public class QuerySqmImpl<R>
|
|||
throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" );
|
||||
}
|
||||
}
|
||||
else if ( sqmStatement instanceof SqmInsertStatement<?> ) {
|
||||
verifyInsertTypesMatch( CRITERIA_HQL_STRING, (SqmInsertStatement<R>) sqmStatement );
|
||||
}
|
||||
|
||||
this.hqlString = CRITERIA_HQL_STRING;
|
||||
this.sqmStatement = sqmStatement;
|
||||
|
@ -422,7 +438,7 @@ public class QuerySqmImpl<R>
|
|||
.getSessionFactoryOptions()
|
||||
.getImmutableEntityUpdateQueryHandlingMode();
|
||||
|
||||
String querySpaces = Arrays.toString( entityDescriptor.getQuerySpaces() );
|
||||
final String querySpaces = Arrays.toString( entityDescriptor.getQuerySpaces() );
|
||||
|
||||
switch ( immutableEntityUpdateQueryHandlingMode ) {
|
||||
case WARNING:
|
||||
|
@ -436,9 +452,65 @@ public class QuerySqmImpl<R>
|
|||
throw new UnsupportedOperationException(
|
||||
"The " + immutableEntityUpdateQueryHandlingMode + " is not supported!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyInsertTypesMatch(String hqlString, SqmInsertStatement<R> sqmStatement) {
|
||||
final List<SqmPath<?>> insertionTargetPaths = sqmStatement.getInsertionTargetPaths();
|
||||
if ( sqmStatement instanceof SqmInsertValuesStatement<?> ) {
|
||||
final SqmInsertValuesStatement<R> statement = (SqmInsertValuesStatement<R>) sqmStatement;
|
||||
for ( SqmValues sqmValues : statement.getValuesList() ) {
|
||||
verifyInsertTypesMatch( hqlString, insertionTargetPaths, sqmValues.getExpressions() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final SqmInsertSelectStatement<R> statement = (SqmInsertSelectStatement<R>) sqmStatement;
|
||||
final List<SqmSelection<?>> selections = statement.getSelectQueryPart()
|
||||
.getFirstQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelections();
|
||||
verifyInsertTypesMatch( hqlString, insertionTargetPaths, selections );
|
||||
statement.getSelectQueryPart().validateQueryStructureAndFetchOwners();
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyInsertTypesMatch(
|
||||
String hqlString,
|
||||
List<SqmPath<?>> insertionTargetPaths,
|
||||
List<? extends SqmTypedNode<?>> expressions) {
|
||||
final int size = insertionTargetPaths.size();
|
||||
final int expressionsSize = expressions.size();
|
||||
if ( size != expressionsSize ) {
|
||||
throw new SemanticException(
|
||||
String.format(
|
||||
"Expected insert attribute count [%d] did not match Query selection count [%d]",
|
||||
size,
|
||||
expressionsSize
|
||||
),
|
||||
hqlString,
|
||||
null
|
||||
);
|
||||
}
|
||||
for ( int i = 0; i < expressionsSize; i++ ) {
|
||||
final SqmTypedNode<?> expression = expressions.get( i );
|
||||
if ( expression.getNodeJavaTypeDescriptor() == null ) {
|
||||
continue;
|
||||
}
|
||||
if ( insertionTargetPaths.get( i ).getJavaTypeDescriptor() != expression.getNodeJavaTypeDescriptor() ) {
|
||||
throw new SemanticException(
|
||||
String.format(
|
||||
"Expected insert attribute type [%s] did not match Query selection type [%s] at selection index [%d]",
|
||||
insertionTargetPaths.get( i ).getJavaTypeDescriptor().getJavaType().getTypeName(),
|
||||
expression.getNodeJavaTypeDescriptor().getJavaType().getTypeName(),
|
||||
i
|
||||
),
|
||||
hqlString,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return getSession().getFactory();
|
||||
|
@ -852,17 +924,16 @@ public class QuerySqmImpl<R>
|
|||
private NonSelectQueryPlan buildInsertQueryPlan() {
|
||||
final SqmInsertStatement<R> sqmInsert = (SqmInsertStatement<R>) getSqmStatement();
|
||||
|
||||
// final String entityNameToUpdate = sqmInsert.getTarget().getReferencedPathSource().getHibernateEntityName();
|
||||
// final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToUpdate );
|
||||
final String entityNameToInsert = sqmInsert.getTarget().getReferencedPathSource().getHibernateEntityName();
|
||||
final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToInsert );
|
||||
|
||||
// final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy();
|
||||
// if ( multiTableStrategy == null ) {
|
||||
final SqmMultiTableInsertStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableInsertStrategy();
|
||||
if ( multiTableStrategy == null ) {
|
||||
return new SimpleInsertQueryPlan( sqmInsert, domainParameterXref );
|
||||
// }
|
||||
// else {
|
||||
//TODO:
|
||||
// return new MultiTableUpdateQueryPlan( sqmInsert, domainParameterXref, multiTableStrategy );
|
||||
// }
|
||||
}
|
||||
else {
|
||||
return new MultiTableInsertQueryPlan( sqmInsert, domainParameterXref, multiTableStrategy );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -444,7 +444,7 @@ public class SqmUtil {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<JpaCriteriaParameter<?>, Supplier<SqmJpaCriteriaParameterWrapper<?>>> getJpaCriteriaParamResolutions() {
|
||||
public Map<JpaCriteriaParameter<?>, SqmJpaCriteriaParameterWrapper<?>> getJpaCriteriaParamResolutions() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
};
|
||||
|
@ -513,7 +513,7 @@ public class SqmUtil {
|
|||
|
||||
private static class ParameterResolutionsImpl implements SqmStatement.ParameterResolutions {
|
||||
private final Set<SqmParameter<?>> sqmParameters;
|
||||
private final Map<JpaCriteriaParameter<?>, Supplier<SqmJpaCriteriaParameterWrapper<?>>> jpaCriteriaParamResolutions;
|
||||
private final Map<JpaCriteriaParameter<?>, SqmJpaCriteriaParameterWrapper<?>> jpaCriteriaParamResolutions;
|
||||
|
||||
public ParameterResolutionsImpl(
|
||||
Set<SqmParameter<?>> sqmParameters,
|
||||
|
@ -527,16 +527,11 @@ public class SqmUtil {
|
|||
this.jpaCriteriaParamResolutions = new IdentityHashMap<>( CollectionHelper.determineProperSizing( jpaCriteriaParamResolutions ) );
|
||||
for ( Map.Entry<JpaCriteriaParameter<?>, List<SqmJpaCriteriaParameterWrapper<?>>> entry : jpaCriteriaParamResolutions.entrySet() ) {
|
||||
final Iterator<SqmJpaCriteriaParameterWrapper<?>> itr = entry.getValue().iterator();
|
||||
this.jpaCriteriaParamResolutions.put(
|
||||
entry.getKey(),
|
||||
() -> {
|
||||
if ( itr.hasNext() ) {
|
||||
return itr.next();
|
||||
if ( !itr.hasNext() ) {
|
||||
throw new IllegalStateException(
|
||||
"SqmJpaCriteriaParameterWrapper references for JpaCriteriaParameter [" + entry.getKey() + "] already exhausted" );
|
||||
}
|
||||
throw new IllegalStateException( "SqmJpaCriteriaParameterWrapper references for JpaCriteriaParameter [" + entry.getKey() + "] already exhausted" );
|
||||
}
|
||||
);
|
||||
|
||||
this.jpaCriteriaParamResolutions.put( entry.getKey(), itr.next() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -547,7 +542,7 @@ public class SqmUtil {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<JpaCriteriaParameter<?>, Supplier<SqmJpaCriteriaParameterWrapper<?>>> getJpaCriteriaParamResolutions() {
|
||||
public Map<JpaCriteriaParameter<?>, SqmJpaCriteriaParameterWrapper<?>> getJpaCriteriaParamResolutions() {
|
||||
return jpaCriteriaParamResolutions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal;
|
||||
|
||||
/**
|
||||
* Handler for dealing with multi-table SQM INSERT queries.
|
||||
*/
|
||||
public interface InsertHandler extends Handler {
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.query.sqm.mutation.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
@ -14,6 +15,7 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
|||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
|
@ -24,6 +26,7 @@ import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
|
|||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
||||
import org.hibernate.query.sqm.tree.update.SqmAssignment;
|
||||
|
@ -163,6 +166,19 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
|||
(Expression) sqmAssignment.getValue().accept( this )
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Specialized hook to visit the assignments defined by the update SQM allow
|
||||
* "listening" for each SQL assignment.
|
||||
*/
|
||||
public AdditionalInsertValues visitInsertionTargetPaths(
|
||||
BiConsumer<Assignable, List<ColumnReference>> targetColumnReferenceConsumer,
|
||||
SqmInsertStatement<?> sqmStatement,
|
||||
EntityPersister entityDescriptor,
|
||||
TableGroup tableGroup,
|
||||
SqmParameterResolutionConsumer parameterResolutionConsumer) {
|
||||
this.parameterResolutionConsumer = parameterResolutionConsumer;
|
||||
return visitInsertionTargetPaths( targetColumnReferenceConsumer, sqmStatement, entityDescriptor, tableGroup );
|
||||
}
|
||||
|
||||
public Predicate visitWhereClause(
|
||||
SqmWhereClause sqmWhereClause,
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
|
@ -61,6 +62,31 @@ public class SqmMutationStrategyHelper {
|
|||
.getFallbackSqmMutationStrategy( rootEntityDescriptor, creationContext );
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard resolution of SqmInsertStrategy to use for a given
|
||||
* entity hierarchy.
|
||||
*/
|
||||
public static SqmMultiTableInsertStrategy resolveInsertStrategy(
|
||||
RootClass entityBootDescriptor,
|
||||
EntityMappingType rootEntityDescriptor,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext();
|
||||
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
|
||||
final SessionFactoryOptions options = sessionFactory.getSessionFactoryOptions();
|
||||
|
||||
final SqmMultiTableInsertStrategy specifiedStrategy = options.getCustomSqmMultiTableInsertStrategy();
|
||||
if ( specifiedStrategy != null ) {
|
||||
return specifiedStrategy;
|
||||
}
|
||||
|
||||
// todo (6.0) : add capability define strategy per-hierarchy
|
||||
|
||||
return sessionFactory.getServiceRegistry().getService( JdbcServices.class )
|
||||
.getJdbcEnvironment()
|
||||
.getDialect()
|
||||
.getFallbackSqmInsertStrategy( rootEntityDescriptor, creationContext );
|
||||
}
|
||||
|
||||
public static void cleanUpCollectionTables(
|
||||
EntityMappingType entityDescriptor,
|
||||
BiFunction<TableReference, PluralAttributeMapping, Predicate> restrictionProducer,
|
||||
|
|
|
@ -45,9 +45,8 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
|||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
@ -74,13 +73,13 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
|||
|
||||
private final SqmCteTable cteTable;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
private final CteStrategy strategy;
|
||||
private final CteMutationStrategy strategy;
|
||||
|
||||
public AbstractCteMutationHandler(
|
||||
SqmCteTable cteTable,
|
||||
SqmDeleteOrUpdateStatement sqmStatement,
|
||||
SqmDeleteOrUpdateStatement<?> sqmStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
CteStrategy strategy,
|
||||
CteMutationStrategy strategy,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( sqmStatement, sessionFactory );
|
||||
this.cteTable = cteTable;
|
||||
|
@ -97,7 +96,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
|||
return domainParameterXref;
|
||||
}
|
||||
|
||||
public CteStrategy getStrategy() {
|
||||
public CteMutationStrategy getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
|
@ -315,18 +314,18 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
|||
|
||||
|
||||
protected TableReference resolveUnionTableReference(
|
||||
TableGroup tableGroup,
|
||||
TableReference tableReference,
|
||||
String tableExpression) {
|
||||
if ( tableGroup instanceof UnionTableGroup ) {
|
||||
if ( tableReference instanceof UnionTableReference ) {
|
||||
return new TableReference(
|
||||
tableExpression,
|
||||
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
|
||||
false,
|
||||
tableReference.getIdentificationVariable(),
|
||||
tableReference.isOptional(),
|
||||
getSessionFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
|
||||
return tableReference;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
|
|||
SqmCteTable cteTable,
|
||||
SqmDeleteStatement<?> sqmDeleteStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
CteStrategy strategy,
|
||||
CteMutationStrategy strategy,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( cteTable, sqmDeleteStatement, domainParameterXref, strategy, sessionFactory );
|
||||
}
|
||||
|
@ -141,8 +141,14 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
|
|||
idSelectCte.getCteTable().getCteColumns(),
|
||||
factory
|
||||
);
|
||||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final TableReference dmlTableReference = resolveUnionTableReference(
|
||||
updatingTableGroup,
|
||||
updatingTableReference,
|
||||
tableExpression
|
||||
);
|
||||
final List<ColumnReference> columnReferences = new ArrayList<>( idSelectCte.getCteTable().getCteColumns().size() );
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.cte;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteTable;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
|
||||
/**
|
||||
* @asciidoc
|
||||
*
|
||||
* {@link SqmMultiTableInsertStrategy} implementation using SQL's modifiable CTE (Common Table Expression)
|
||||
* approach to perform the update/delete. E.g. (using delete):
|
||||
*
|
||||
* This strategy will create a query like this:
|
||||
*
|
||||
* ```
|
||||
* with hte_entity as (
|
||||
* select *, next value for sequence from ...
|
||||
* ),
|
||||
* dml_cte_1 as (
|
||||
* insert into base_table select e.id, e.base from hte_entity e
|
||||
* returning id
|
||||
* ),
|
||||
* dml_cte_2 as (
|
||||
* insert into sub_table select e.id, e.sub1 from hte_entity e
|
||||
* returning id
|
||||
* )
|
||||
* select count(*) from dml_cte_1
|
||||
* ```
|
||||
*
|
||||
* if the sequence generator has an optimizer, the optimizer is implemented in SQL like this:
|
||||
*
|
||||
* ```
|
||||
* with hte_entity_raw as (
|
||||
* select *, row_number() over() from ...
|
||||
* ),
|
||||
* rows_with_next_val(rn, val) as (
|
||||
* -- then, fetch a sequence value for every row number that needs it
|
||||
* select rn, next value for sequence FROM rows_needing_next_val
|
||||
* where (e.rn-1) % [incrementSize] = 0
|
||||
* ),
|
||||
* hte_entity as (
|
||||
* select e.*, t.val + (e.rn - t.rn) as id
|
||||
* from hte_entity_raw e
|
||||
* -- join the data against the generated sequence value, based on the row number group they belong to
|
||||
* -- i.e. where the row number is within the increment size
|
||||
* left join rows_with_next_val t ON e.rn - ((e.rn-1) % 10) = t.rn
|
||||
* ),
|
||||
* dml_cte_1 as (
|
||||
* insert into base_table select e.id, e.base from hte_entity e
|
||||
* returning id
|
||||
* ),
|
||||
* dml_cte_2 as (
|
||||
* insert into sub_table select e.id, e.sub1 from hte_entity e
|
||||
* returning id
|
||||
* )
|
||||
* select count(*) from dml_cte_1
|
||||
* ```
|
||||
*
|
||||
* in case the id generator uses identity generation, a row number will be created which should ensure insert ordering
|
||||
*
|
||||
* ```
|
||||
* with hte_entity_raw as (
|
||||
* select *, row_number() over() from ...
|
||||
* ),
|
||||
* dml_cte_1 as (
|
||||
* insert into base_table select e.id, e.base from hte_entity_raw e
|
||||
* returning id, e.row_number
|
||||
* ),
|
||||
* with hte_entity as (
|
||||
* select * from hte_entity e join dml_cte_1 c on e.row_number = c.row_number
|
||||
* ),
|
||||
* dml_cte_2 as (
|
||||
* insert into sub_table select c.id, e.sub1 from hte_entity e
|
||||
* returning id
|
||||
* )
|
||||
* select count(*) from dml_cte_1
|
||||
* ```
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class CteInsertStrategy implements SqmMultiTableInsertStrategy {
|
||||
public static final String SHORT_NAME = "cte";
|
||||
|
||||
private final EntityPersister rootDescriptor;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final SqmCteTable entityCteTable;
|
||||
|
||||
public CteInsertStrategy(
|
||||
EntityMappingType rootEntityType,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
this( rootEntityType.getEntityPersister(), runtimeModelCreationContext );
|
||||
}
|
||||
|
||||
public CteInsertStrategy(
|
||||
EntityPersister rootDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
this.rootDescriptor = rootDescriptor;
|
||||
this.sessionFactory = runtimeModelCreationContext.getSessionFactory();
|
||||
|
||||
final Dialect dialect = sessionFactory.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getJdbcEnvironment()
|
||||
.getDialect();
|
||||
|
||||
if ( !dialect.supportsNonQueryWithCTE() ) {
|
||||
throw new UnsupportedOperationException(
|
||||
getClass().getSimpleName() +
|
||||
" can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well"
|
||||
);
|
||||
}
|
||||
|
||||
if ( !dialect.supportsValuesList() ) {
|
||||
throw new UnsupportedOperationException(
|
||||
getClass().getSimpleName() +
|
||||
" can only be used with Dialects that support VALUES lists"
|
||||
);
|
||||
}
|
||||
|
||||
// The table name might be a sub-query, which is inappropriate for a temporary table name
|
||||
final String originalTableName = rootDescriptor.getEntityPersister().getSynchronizedQuerySpaces()[0];
|
||||
final String name;
|
||||
if ( Identifier.isQuoted( originalTableName ) ) {
|
||||
name = dialect.quote( TemporaryTable.ENTITY_TABLE_PREFIX + Identifier.unQuote( originalTableName ) );
|
||||
}
|
||||
else {
|
||||
name = TemporaryTable.ENTITY_TABLE_PREFIX + originalTableName;
|
||||
}
|
||||
final String qualifiedTableName;
|
||||
if ( name.length() > dialect.getMaxIdentifierLength() ) {
|
||||
qualifiedTableName = name.substring( 0, dialect.getMaxIdentifierLength() );
|
||||
}
|
||||
else {
|
||||
qualifiedTableName = name;
|
||||
}
|
||||
this.entityCteTable = SqmCteTable.createEntityTable( qualifiedTableName, rootDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeInsert(
|
||||
SqmInsertStatement<?> sqmInsertStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new CteInsertHandler( entityCteTable, sqmInsertStatement, domainParameterXref, sessionFactory ).execute( context );
|
||||
}
|
||||
}
|
|
@ -50,21 +50,21 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
|||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class CteStrategy implements SqmMultiTableMutationStrategy {
|
||||
public class CteMutationStrategy implements SqmMultiTableMutationStrategy {
|
||||
public static final String SHORT_NAME = "cte";
|
||||
public static final String TABLE_NAME = "id_cte";
|
||||
public static final String ID_TABLE_NAME = "id_cte";
|
||||
|
||||
private final EntityPersister rootDescriptor;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final SqmCteTable cteTable;
|
||||
private final SqmCteTable idCteTable;
|
||||
|
||||
public CteStrategy(
|
||||
public CteMutationStrategy(
|
||||
EntityMappingType rootEntityType,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
this( rootEntityType.getEntityPersister(), runtimeModelCreationContext );
|
||||
}
|
||||
|
||||
public CteStrategy(
|
||||
public CteMutationStrategy(
|
||||
EntityPersister rootDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
this.rootDescriptor = rootDescriptor;
|
||||
|
@ -89,28 +89,28 @@ public class CteStrategy implements SqmMultiTableMutationStrategy {
|
|||
);
|
||||
}
|
||||
|
||||
this.cteTable = new SqmCteTable( TABLE_NAME, rootDescriptor );
|
||||
this.idCteTable = SqmCteTable.createIdTable( ID_TABLE_NAME, rootDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
SqmDeleteStatement<?> sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
checkMatch( sqmDelete );
|
||||
return new CteDeleteHandler( cteTable, sqmDelete, domainParameterXref, this, sessionFactory ).execute( context );
|
||||
return new CteDeleteHandler( idCteTable, sqmDelete, domainParameterXref, this, sessionFactory ).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
SqmUpdateStatement<?> sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
checkMatch( sqmUpdate );
|
||||
return new CteUpdateHandler( cteTable, sqmUpdate, domainParameterXref, this, sessionFactory ).execute( context );
|
||||
return new CteUpdateHandler( idCteTable, sqmUpdate, domainParameterXref, this, sessionFactory ).execute( context );
|
||||
}
|
||||
|
||||
private void checkMatch(SqmDeleteOrUpdateStatement sqmStatement) {
|
||||
private void checkMatch(SqmDeleteOrUpdateStatement<?> sqmStatement) {
|
||||
final String targetEntityName = sqmStatement.getTarget().getEntityName();
|
||||
final EntityPersister targetEntityDescriptor = sessionFactory.getDomainModel().getEntityDescriptor( targetEntityName );
|
||||
|
|
@ -18,6 +18,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
import org.hibernate.query.sqm.mutation.internal.UpdateHandler;
|
||||
|
@ -34,7 +35,6 @@ import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
|||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||
import org.hibernate.sql.ast.tree.update.Assignment;
|
||||
import org.hibernate.sql.ast.tree.update.UpdateStatement;
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
SqmCteTable cteTable,
|
||||
SqmUpdateStatement sqmStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
CteStrategy strategy,
|
||||
CteMutationStrategy strategy,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( cteTable, sqmStatement, domainParameterXref, strategy, sessionFactory );
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
collectTableReference( updatingTableGroup.getTableReferenceJoins().get( i ), tableReferenceByAlias::put );
|
||||
}
|
||||
|
||||
final Map<String, List<Assignment>> assignmentsByTable = CollectionHelper.mapOfSize(
|
||||
final Map<TableReference, List<Assignment>> assignmentsByTable = CollectionHelper.mapOfSize(
|
||||
updatingTableGroup.getTableReferenceJoins().size() + 1
|
||||
);
|
||||
|
||||
|
@ -111,11 +111,11 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
final Assignment assignment = assignments.get( i );
|
||||
final List<ColumnReference> assignmentColumnRefs = assignment.getAssignable().getColumnReferences();
|
||||
|
||||
String assignmentTableReference = null;
|
||||
TableReference assignmentTableReference = null;
|
||||
|
||||
for ( int c = 0; c < assignmentColumnRefs.size(); c++ ) {
|
||||
final ColumnReference columnReference = assignmentColumnRefs.get( c );
|
||||
final String tableReference = resolveTableReference(
|
||||
final TableReference tableReference = resolveTableReference(
|
||||
columnReference,
|
||||
tableReferenceByAlias
|
||||
);
|
||||
|
@ -144,18 +144,18 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
idSelectCte.getCteTable().getCteColumns(),
|
||||
factory
|
||||
);
|
||||
final List<Assignment> assignmentList;
|
||||
if ( updatingTableGroup instanceof UnionTableGroup ) {
|
||||
assignmentList = assignmentsByTable.get( updatingTableGroup.getPrimaryTableReference().getTableExpression() );
|
||||
}
|
||||
else {
|
||||
assignmentList = assignmentsByTable.get( tableExpression );
|
||||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final List<Assignment> assignmentList = assignmentsByTable.get( updatingTableReference );
|
||||
if ( assignmentList == null ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final TableReference dmlTableReference = resolveUnionTableReference(
|
||||
updatingTableGroup,
|
||||
updatingTableReference,
|
||||
tableExpression
|
||||
);
|
||||
final List<ColumnReference> columnReferences = new ArrayList<>( idSelectCte.getCteTable().getCteColumns().size() );
|
||||
|
@ -191,15 +191,14 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
collectTableReference( tableReferenceJoin.getJoinedTableReference(), consumer );
|
||||
}
|
||||
|
||||
private String resolveTableReference(
|
||||
private TableReference resolveTableReference(
|
||||
ColumnReference columnReference,
|
||||
Map<String, TableReference> tableReferenceByAlias) {
|
||||
final String qualifier = columnReference.getQualifier();
|
||||
final TableReference tableReferenceByQualifier = tableReferenceByAlias.get( qualifier );
|
||||
final TableReference tableReferenceByQualifier = tableReferenceByAlias.get( columnReference.getQualifier() );
|
||||
if ( tableReferenceByQualifier != null ) {
|
||||
return tableReferenceByQualifier.getTableExpression();
|
||||
return tableReferenceByQualifier;
|
||||
}
|
||||
|
||||
return qualifier;
|
||||
throw new SemanticException( "Assignment referred to column of a joined association: " + columnReference );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.relational.Exportable;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Contributable;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdTable implements Exportable, Contributable {
|
||||
|
||||
public static final String DEFAULT_ALIAS = "idtable_";
|
||||
|
||||
private final EntityMappingType entityDescriptor;
|
||||
private final String qualifiedTableName;
|
||||
|
||||
private IdTableSessionUidColumn sessionUidColumn;
|
||||
private final List<IdTableColumn> columns = new ArrayList<>();
|
||||
|
||||
private final Dialect dialect;
|
||||
|
||||
public IdTable(
|
||||
EntityMappingType entityDescriptor,
|
||||
Function<String, String> idTableNameAdjuster,
|
||||
Dialect dialect,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
this.entityDescriptor = entityDescriptor;
|
||||
|
||||
// The table name might be a sub-query, which is inappropriate for an id table name
|
||||
final String originalTableName = entityDescriptor.getEntityPersister().getSynchronizedQuerySpaces()[0];
|
||||
if ( Identifier.isQuoted( originalTableName ) ) {
|
||||
this.qualifiedTableName = dialect.quote( idTableNameAdjuster.apply( Identifier.unQuote( originalTableName ) ) );
|
||||
}
|
||||
else {
|
||||
this.qualifiedTableName = idTableNameAdjuster.apply( originalTableName );
|
||||
}
|
||||
|
||||
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
|
||||
.getEntityBinding( entityDescriptor.getEntityName() );
|
||||
|
||||
final Iterator<Column> itr = entityBinding.getTable().getPrimaryKey().getColumnIterator();
|
||||
final Iterator<JdbcMapping> jdbcMappings = entityDescriptor.getIdentifierMapping().getJdbcMappings().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final Column column = itr.next();
|
||||
final JdbcMapping jdbcMapping = jdbcMappings.next();
|
||||
columns.add(
|
||||
new IdTableColumn(
|
||||
this,
|
||||
column.getText( dialect ),
|
||||
jdbcMapping,
|
||||
column.getSqlType( dialect, runtimeModelCreationContext.getMetadata() )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
entityDescriptor.visitSubTypeAttributeMappings(
|
||||
attribute -> {
|
||||
if ( attribute instanceof PluralAttributeMapping ) {
|
||||
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute;
|
||||
|
||||
if ( pluralAttribute.getSeparateCollectionTable() != null ) {
|
||||
// Ensure that the FK target columns are available
|
||||
final ModelPart fkTarget = pluralAttribute.getKeyDescriptor().getTargetPart();
|
||||
if ( !( fkTarget instanceof EntityIdentifierMapping ) ) {
|
||||
final Value value = entityBinding.getSubclassProperty( pluralAttribute.getAttributeName() )
|
||||
.getValue();
|
||||
final Iterator<Selectable> columnIterator = ( (Collection) value ).getKey()
|
||||
.getColumnIterator();
|
||||
fkTarget.forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
final Selectable selectable = columnIterator.next();
|
||||
if ( selectable instanceof Column ) {
|
||||
columns.add(
|
||||
new IdTableColumn(
|
||||
this,
|
||||
selectable.getText( dialect ),
|
||||
selection.getJdbcMapping(),
|
||||
( (Column) selectable ).getSqlType(
|
||||
dialect,
|
||||
runtimeModelCreationContext.getMetadata()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
public EntityMappingType getEntityDescriptor() {
|
||||
return entityDescriptor;
|
||||
}
|
||||
|
||||
public String getQualifiedTableName() {
|
||||
return qualifiedTableName;
|
||||
}
|
||||
|
||||
public List<IdTableColumn> getIdTableColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public IdTableSessionUidColumn getSessionUidColumn() {
|
||||
return sessionUidColumn;
|
||||
}
|
||||
|
||||
public String getTableExpression() {
|
||||
return qualifiedTableName;
|
||||
}
|
||||
|
||||
public void addColumn(IdTableColumn column) {
|
||||
columns.add( column );
|
||||
if ( column instanceof IdTableSessionUidColumn ) {
|
||||
this.sessionUidColumn = (IdTableSessionUidColumn) column;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContributor() {
|
||||
return entityDescriptor.getContributor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return getQualifiedTableName();
|
||||
}
|
||||
|
||||
public Dialect getDialect() {
|
||||
return this.dialect;
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
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.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
||||
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 LocalTemporaryTableStrategy implements SqmMultiTableMutationStrategy {
|
||||
private static final Logger log = Logger.getLogger( LocalTemporaryTableStrategy.class );
|
||||
|
||||
public static final String SHORT_NAME = "local_temporary";
|
||||
public static final String DROP_ID_TABLES = "hibernate.hql.bulk_id_strategy.local_temporary.drop_tables";
|
||||
|
||||
private final IdTable idTable;
|
||||
private final Supplier<IdTableExporter> idTableExporterAccess;
|
||||
private final AfterUseAction afterUseAction;
|
||||
private final TempTableDdlTransactionHandling ddlTransactionHandling;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private boolean dropIdTables;
|
||||
|
||||
public LocalTemporaryTableStrategy(
|
||||
IdTable idTable,
|
||||
Supplier<IdTableExporter> idTableExporterAccess,
|
||||
AfterUseAction afterUseAction,
|
||||
TempTableDdlTransactionHandling ddlTransactionHandling,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.idTable = idTable;
|
||||
this.idTableExporterAccess = idTableExporterAccess;
|
||||
this.afterUseAction = afterUseAction;
|
||||
this.ddlTransactionHandling = ddlTransactionHandling;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
public LocalTemporaryTableStrategy(
|
||||
IdTable idTable,
|
||||
Function<Integer, String> databaseTypeNameResolver,
|
||||
AfterUseAction afterUseAction,
|
||||
TempTableDdlTransactionHandling ddlTransactionHandling,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this(
|
||||
idTable,
|
||||
() -> new TempIdTableExporter( true, databaseTypeNameResolver ),
|
||||
afterUseAction,
|
||||
ddlTransactionHandling,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
idTable,
|
||||
session -> {
|
||||
throw new UnsupportedOperationException( "Unexpected call to access Session uid" );
|
||||
},
|
||||
idTableExporterAccess,
|
||||
BeforeUseAction.CREATE,
|
||||
afterUseAction,
|
||||
ddlTransactionHandling,
|
||||
sessionFactory
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
idTable,
|
||||
session -> {
|
||||
throw new UnsupportedOperationException( "Unexpected call to access Session uid" );
|
||||
},
|
||||
idTableExporterAccess,
|
||||
BeforeUseAction.CREATE,
|
||||
afterUseAction,
|
||||
ddlTransactionHandling,
|
||||
sessionFactory
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(
|
||||
MappingModelCreationProcess mappingModelCreationProcess,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
final ConfigurationService configService = mappingModelCreationProcess.getCreationContext()
|
||||
.getBootstrapContext()
|
||||
.getServiceRegistry().getService( ConfigurationService.class );
|
||||
this.dropIdTables = configService.getSetting(
|
||||
DROP_ID_TABLES,
|
||||
StandardConverters.BOOLEAN,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
if ( !dropIdTables ) {
|
||||
return;
|
||||
}
|
||||
|
||||
dropIdTables = false;
|
||||
|
||||
log.debugf( "Dropping local-temp ID table : %s", idTable.getTableExpression() );
|
||||
|
||||
final IdTableHelper.IdTableDropWork idTableDropWork = new IdTableHelper.IdTableDropWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
sessionFactory
|
||||
);
|
||||
Connection connection;
|
||||
try {
|
||||
connection = connectionAccess.obtainConnection();
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
// assume this comes from org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl
|
||||
log.debugf( "Unable to obtain JDBC connection; unable to drop local-temp ID table : %s", idTable.getTableExpression() );
|
||||
return;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable obtain JDBC Connection", e );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
idTableDropWork.execute( connection );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connectionAccess.releaseConnection( connection );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class PhysicalIdTableExporter implements IdTableExporter {
|
||||
|
||||
protected String getCreateCommand() {
|
||||
return "create table";
|
||||
}
|
||||
|
||||
protected String getCreateOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getDropCommand() {
|
||||
return "drop table";
|
||||
}
|
||||
|
||||
protected String getTruncateIdTableCommand(){
|
||||
return "delete from";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlCreateCommand(IdTable idTable) {
|
||||
final StringBuilder buffer = new StringBuilder( getCreateCommand() ).append( ' ' );
|
||||
buffer.append( idTable.getQualifiedTableName() );
|
||||
buffer.append( '(' );
|
||||
|
||||
boolean firstPass = true;
|
||||
for ( IdTableColumn column : idTable.getIdTableColumns() ) {
|
||||
if ( firstPass ) {
|
||||
firstPass = false;
|
||||
}
|
||||
else {
|
||||
buffer.append( ", " );
|
||||
}
|
||||
|
||||
buffer.append( column.getColumnName() ).append( ' ' );
|
||||
buffer.append( column.getSqlTypeDefinition() );
|
||||
// id values cannot be null
|
||||
buffer.append( " not null" );
|
||||
}
|
||||
|
||||
buffer.append( ") " );
|
||||
|
||||
final String createOptions = getCreateOptions();
|
||||
if ( createOptions != null ) {
|
||||
buffer.append( createOptions );
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlDropCommand(IdTable idTable) {
|
||||
return getDropCommand() + ' ' + idTable.getQualifiedTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlTruncateCommand(
|
||||
IdTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( idTable.getSessionUidColumn() != null ) {
|
||||
assert sessionUidAccess != null;
|
||||
final String uid = sessionUidAccess.apply( session );
|
||||
return getTruncateIdTableCommand() + " " + idTable.getQualifiedTableName()
|
||||
+ " where " + idTable.getSessionUidColumn().getColumnName() + " = " + uid;
|
||||
}
|
||||
else {
|
||||
return getTruncateIdTableCommand() + " " + idTable.getQualifiedTableName();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class TempIdTableExporter implements IdTableExporter {
|
||||
private final boolean isLocal;
|
||||
private final Function<Integer, String> databaseTypeNameResolver;
|
||||
|
||||
public TempIdTableExporter(
|
||||
boolean isLocal,
|
||||
Function<Integer, String> databaseTypeNameResolver) {
|
||||
this.isLocal = isLocal;
|
||||
this.databaseTypeNameResolver = databaseTypeNameResolver;
|
||||
}
|
||||
|
||||
protected String getCreateCommand() {
|
||||
return "create " + (isLocal ? "local" : "global") + " temporary table";
|
||||
}
|
||||
|
||||
protected String getCreateOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getDropCommand() {
|
||||
return "drop table";
|
||||
}
|
||||
|
||||
protected String getTruncateIdTableCommand(){
|
||||
return "delete from";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlCreateCommand(IdTable idTable) {
|
||||
final StringBuilder buffer = new StringBuilder( getCreateCommand() ).append( ' ' );
|
||||
buffer.append( idTable.getQualifiedTableName() );
|
||||
buffer.append( '(' );
|
||||
|
||||
boolean firstPass = true;
|
||||
for ( IdTableColumn column : idTable.getIdTableColumns() ) {
|
||||
if ( firstPass ) {
|
||||
firstPass = false;
|
||||
}
|
||||
else {
|
||||
buffer.append( ", " );
|
||||
}
|
||||
|
||||
buffer.append( column.getColumnName() ).append( ' ' );
|
||||
final int sqlTypeCode = column.getJdbcMapping().getJdbcTypeDescriptor().getDefaultSqlTypeCode();
|
||||
final String databaseTypeName = column.getSqlTypeDefinition();
|
||||
|
||||
buffer.append( " " ).append( databaseTypeName ).append( " " );
|
||||
|
||||
final String columnAnnotation = idTable.getDialect().getCreateTemporaryTableColumnAnnotation( sqlTypeCode );
|
||||
if ( !columnAnnotation.isEmpty() ) {
|
||||
buffer.append(" ").append( columnAnnotation );
|
||||
}
|
||||
|
||||
// id values cannot be null
|
||||
buffer.append( " not null" );
|
||||
}
|
||||
|
||||
buffer.append( ") " );
|
||||
|
||||
final String createOptions = getCreateOptions();
|
||||
if ( createOptions != null ) {
|
||||
buffer.append( createOptions );
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlDropCommand(IdTable idTable) {
|
||||
return getDropCommand() + " " + idTable.getQualifiedTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlTruncateCommand(
|
||||
IdTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( idTable.getSessionUidColumn() != null ) {
|
||||
assert sessionUidAccess != null;
|
||||
final String uid = sessionUidAccess.apply( session );
|
||||
return getTruncateIdTableCommand() + " " + idTable.getQualifiedTableName()
|
||||
+ " where " + idTable.getSessionUidColumn().getColumnName() + " = " + uid;
|
||||
}
|
||||
else {
|
||||
return getTruncateIdTableCommand() + " " + idTable.getQualifiedTableName();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,10 +25,10 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class InlineStrategy implements SqmMultiTableMutationStrategy {
|
||||
public class InlineMutationStrategy implements SqmMultiTableMutationStrategy {
|
||||
private final Function<SqmDeleteOrUpdateStatement,MatchingIdRestrictionProducer> matchingIdsStrategy;
|
||||
|
||||
public InlineStrategy(Dialect dialect) {
|
||||
public InlineMutationStrategy(Dialect dialect) {
|
||||
this( determinePredicateProducer( dialect ) );
|
||||
}
|
||||
|
||||
|
@ -36,13 +36,13 @@ public class InlineStrategy implements SqmMultiTableMutationStrategy {
|
|||
return statement -> new InPredicateRestrictionProducer();
|
||||
}
|
||||
|
||||
public InlineStrategy(Function<SqmDeleteOrUpdateStatement,MatchingIdRestrictionProducer> matchingIdsStrategy) {
|
||||
public InlineMutationStrategy(Function<SqmDeleteOrUpdateStatement,MatchingIdRestrictionProducer> matchingIdsStrategy) {
|
||||
this.matchingIdsStrategy = matchingIdsStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
SqmUpdateStatement<?> sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
final InlineUpdateHandler handler = new InlineUpdateHandler(
|
||||
|
@ -56,7 +56,7 @@ public class InlineStrategy implements SqmMultiTableMutationStrategy {
|
|||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
SqmDeleteStatement<?> sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
final InlineDeleteHandler deleteHandler = new InlineDeleteHandler(
|
|
@ -4,10 +4,10 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
/**
|
||||
* Actions to perform in regards to an id-table after each use.
|
||||
* Actions to perform in regards to an temporary table after each use.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
|
@ -4,10 +4,10 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
/**
|
||||
* Actions to perform in regards to an id-table prior to each use.
|
||||
* Actions to perform in regards to a temporary table prior to each use.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
|
@ -4,14 +4,17 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableColumn;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -44,14 +47,14 @@ import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public final class ExecuteWithIdTableHelper {
|
||||
private ExecuteWithIdTableHelper() {
|
||||
public final class ExecuteWithTemporaryTableHelper {
|
||||
private ExecuteWithTemporaryTableHelper() {
|
||||
}
|
||||
|
||||
public static int saveMatchingIdsIntoIdTable(
|
||||
MultiTableSqmMutationConverter sqmConverter,
|
||||
Predicate suppliedPredicate,
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
ExecutionContext executionContext) {
|
||||
|
@ -62,11 +65,16 @@ public final class ExecuteWithIdTableHelper {
|
|||
assert mutatingTableGroup.getModelPart() instanceof EntityMappingType;
|
||||
final EntityMappingType mutatingEntityDescriptor = (EntityMappingType) mutatingTableGroup.getModelPart();
|
||||
|
||||
final TableReference idTableReference = new TableReference( idTable.getTableExpression(), null, false, factory );
|
||||
final TableReference idTableReference = new TableReference(
|
||||
idTable.getTableExpression(),
|
||||
null,
|
||||
false,
|
||||
factory
|
||||
);
|
||||
final InsertStatement idTableInsert = new InsertStatement( idTableReference );
|
||||
|
||||
for ( int i = 0; i < idTable.getIdTableColumns().size(); i++ ) {
|
||||
final IdTableColumn column = idTable.getIdTableColumns().get( i );
|
||||
for ( int i = 0; i < idTable.getColumns().size(); i++ ) {
|
||||
final TemporaryTableColumn column = idTable.getColumns().get( i );
|
||||
idTableInsert.addTargetColumnReferences(
|
||||
new ColumnReference(
|
||||
idTableReference,
|
||||
|
@ -97,7 +105,10 @@ public final class ExecuteWithIdTableHelper {
|
|||
jdbcPosition,
|
||||
jdbcPosition + 1,
|
||||
sqmConverter.getSqlExpressionResolver().resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey( tableReference, selection.getSelectionExpression() ),
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
tableReference,
|
||||
selection.getSelectionExpression()
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
tableReference,
|
||||
selection,
|
||||
|
@ -124,7 +135,14 @@ public final class ExecuteWithIdTableHelper {
|
|||
}
|
||||
|
||||
matchingIdSelection.applyPredicate( suppliedPredicate );
|
||||
return saveIntoTemporaryTable( idTableInsert, jdbcParameterBindings, executionContext );
|
||||
}
|
||||
|
||||
public static int saveIntoTemporaryTable(
|
||||
InsertStatement temporaryTableInsert,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
ExecutionContext executionContext) {
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final JdbcServices jdbcServices = factory.getJdbcServices();
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
|
@ -133,8 +151,11 @@ public final class ExecuteWithIdTableHelper {
|
|||
// Acquire a WRITE lock for the rows that are about to be modified
|
||||
lockOptions.setLockMode( LockMode.WRITE );
|
||||
// Visit the table joins and reset the lock mode if we encounter OUTER joins that are not supported
|
||||
if ( !jdbcEnvironment.getDialect().supportsOuterJoinForUpdate() ) {
|
||||
matchingIdSelection.getFromClause().visitTableJoins(
|
||||
if ( temporaryTableInsert.getSourceSelectStatement() != null
|
||||
&& !jdbcEnvironment.getDialect().supportsOuterJoinForUpdate() ) {
|
||||
temporaryTableInsert.getSourceSelectStatement().forEachQuerySpec(
|
||||
querySpec -> {
|
||||
querySpec.getFromClause().visitTableJoins(
|
||||
tableJoin -> {
|
||||
if ( tableJoin.getJoinType() != SqlAstJoinType.INNER ) {
|
||||
lockOptions.setLockMode( lockMode );
|
||||
|
@ -142,7 +163,9 @@ public final class ExecuteWithIdTableHelper {
|
|||
}
|
||||
);
|
||||
}
|
||||
final JdbcInsert jdbcInsert = sqlAstTranslatorFactory.buildInsertTranslator( factory, idTableInsert )
|
||||
);
|
||||
}
|
||||
final JdbcInsert jdbcInsert = sqlAstTranslatorFactory.buildInsertTranslator( factory, temporaryTableInsert )
|
||||
.translate( jdbcParameterBindings, executionContext.getQueryOptions() );
|
||||
lockOptions.setLockMode( lockMode );
|
||||
|
||||
|
@ -159,7 +182,7 @@ public final class ExecuteWithIdTableHelper {
|
|||
}
|
||||
|
||||
public static QuerySpec createIdTableSelectQuerySpec(
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
EntityMappingType entityDescriptor,
|
||||
ExecutionContext executionContext) {
|
||||
|
@ -167,7 +190,7 @@ public final class ExecuteWithIdTableHelper {
|
|||
}
|
||||
|
||||
public static QuerySpec createIdTableSelectQuerySpec(
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
ModelPart fkModelPart,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
EntityMappingType entityDescriptor,
|
||||
|
@ -176,7 +199,7 @@ public final class ExecuteWithIdTableHelper {
|
|||
|
||||
final TableReference idTableReference = new TableReference(
|
||||
idTable.getTableExpression(),
|
||||
IdTable.DEFAULT_ALIAS,
|
||||
TemporaryTable.DEFAULT_ALIAS,
|
||||
true,
|
||||
executionContext.getSession().getFactory()
|
||||
);
|
||||
|
@ -201,25 +224,25 @@ public final class ExecuteWithIdTableHelper {
|
|||
private static void applyIdTableSelections(
|
||||
QuerySpec querySpec,
|
||||
TableReference tableReference,
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
ModelPart fkModelPart,
|
||||
ExecutionContext executionContext) {
|
||||
if ( fkModelPart == null ) {
|
||||
final int size = idTable.getEntityDescriptor().getIdentifierMapping().getJdbcTypeCount();
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final IdTableColumn idTableColumn = idTable.getIdTableColumns().get( i );
|
||||
if ( idTableColumn != idTable.getSessionUidColumn() ) {
|
||||
final TemporaryTableColumn temporaryTableColumn = idTable.getColumns().get( i );
|
||||
if ( temporaryTableColumn != idTable.getSessionUidColumn() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
i + 1,
|
||||
i,
|
||||
new ColumnReference(
|
||||
tableReference,
|
||||
idTableColumn.getColumnName(),
|
||||
temporaryTableColumn.getColumnName(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
idTableColumn.getJdbcMapping(),
|
||||
temporaryTableColumn.getJdbcMapping(),
|
||||
executionContext.getSession().getFactory()
|
||||
)
|
||||
)
|
||||
|
@ -253,7 +276,7 @@ public final class ExecuteWithIdTableHelper {
|
|||
private static void applyIdTableRestrictions(
|
||||
QuerySpec querySpec,
|
||||
TableReference idTableReference,
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
ExecutionContext executionContext) {
|
||||
if ( idTable.getSessionUidColumn() != null ) {
|
||||
|
@ -278,21 +301,20 @@ public final class ExecuteWithIdTableHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static void performBeforeIdTableUseActions(
|
||||
BeforeUseAction beforeUseAction,
|
||||
IdTable idTable,
|
||||
Supplier<IdTableExporter> idTableExporterAccess,
|
||||
TempTableDdlTransactionHandling ddlTransactionHandling,
|
||||
public static void performBeforeTemporaryTableUseActions(
|
||||
TemporaryTable temporaryTable,
|
||||
ExecutionContext executionContext) {
|
||||
if ( beforeUseAction == BeforeUseAction.CREATE ) {
|
||||
final IdTableHelper.IdTableCreationWork idTableCreationWork = new IdTableHelper.IdTableCreationWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
executionContext.getSession().getFactory()
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final Dialect dialect = factory.getJdbcServices().getDialect();
|
||||
if ( dialect.getTemporaryTableBeforeUseAction() == BeforeUseAction.CREATE ) {
|
||||
final TemporaryTableHelper.TemporaryTableCreationWork temporaryTableCreationWork = new TemporaryTableHelper.TemporaryTableCreationWork(
|
||||
temporaryTable,
|
||||
factory
|
||||
);
|
||||
|
||||
final TempTableDdlTransactionHandling ddlTransactionHandling = dialect.getTemporaryTableDdlTransactionHandling();
|
||||
if ( ddlTransactionHandling == TempTableDdlTransactionHandling.NONE ) {
|
||||
executionContext.getSession().doWork( idTableCreationWork );
|
||||
executionContext.getSession().doWork( temporaryTableCreationWork );
|
||||
}
|
||||
else {
|
||||
final IsolationDelegate isolationDelegate = executionContext.getSession()
|
||||
|
@ -300,35 +322,35 @@ public final class ExecuteWithIdTableHelper {
|
|||
.getJdbcSessionOwner()
|
||||
.getTransactionCoordinator()
|
||||
.createIsolationDelegate();
|
||||
isolationDelegate.delegateWork( idTableCreationWork, ddlTransactionHandling == TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT );
|
||||
isolationDelegate.delegateWork( temporaryTableCreationWork, ddlTransactionHandling == TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void performAfterIdTableUseActions(
|
||||
AfterUseAction afterUseAction,
|
||||
IdTable idTable,
|
||||
Supplier<IdTableExporter> idTableExporterAccess,
|
||||
TempTableDdlTransactionHandling ddlTransactionHandling,
|
||||
public static void performAfterTemporaryTableUseActions(
|
||||
TemporaryTable temporaryTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
ExecutionContext executionContext) {
|
||||
if ( afterUseAction == AfterUseAction.CLEAN ) {
|
||||
IdTableHelper.cleanIdTableRows(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final Dialect dialect = factory.getJdbcServices().getDialect();
|
||||
switch ( dialect.getTemporaryTableAfterUseAction() ) {
|
||||
case CLEAN:
|
||||
TemporaryTableHelper.cleanTemporaryTableRows(
|
||||
temporaryTable,
|
||||
dialect.getTemporaryTableExporter(),
|
||||
sessionUidAccess,
|
||||
executionContext.getSession()
|
||||
);
|
||||
}
|
||||
else if ( afterUseAction == AfterUseAction.DROP ) {
|
||||
final IdTableHelper.IdTableDropWork idTableDropWork = new IdTableHelper.IdTableDropWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
executionContext.getSession().getFactory()
|
||||
break;
|
||||
case DROP:
|
||||
final TemporaryTableHelper.TemporaryTableDropWork temporaryTableDropWork = new TemporaryTableHelper.TemporaryTableDropWork(
|
||||
temporaryTable,
|
||||
factory
|
||||
);
|
||||
|
||||
final TempTableDdlTransactionHandling ddlTransactionHandling = dialect.getTemporaryTableDdlTransactionHandling();
|
||||
if ( ddlTransactionHandling == TempTableDdlTransactionHandling.NONE ) {
|
||||
executionContext.getSession().doWork( idTableDropWork );
|
||||
executionContext.getSession().doWork( temporaryTableDropWork );
|
||||
}
|
||||
else {
|
||||
final IsolationDelegate isolationDelegate = executionContext.getSession()
|
||||
|
@ -336,7 +358,10 @@ public final class ExecuteWithIdTableHelper {
|
|||
.getJdbcSessionOwner()
|
||||
.getTransactionCoordinator()
|
||||
.createIsolationDelegate();
|
||||
isolationDelegate.delegateWork( idTableDropWork, ddlTransactionHandling == TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT );
|
||||
isolationDelegate.delegateWork(
|
||||
temporaryTableDropWork,
|
||||
ddlTransactionHandling == TempTableDdlTransactionHandling.ISOLATE_AND_TRANSACT
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,9 +4,8 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
|
||||
/**
|
||||
* Strategy based on ANSI SQL's definition of a "global temporary table".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GlobalTemporaryTableInsertStrategy extends GlobalTemporaryTableStrategy implements SqmMultiTableInsertStrategy {
|
||||
|
||||
public GlobalTemporaryTableInsertStrategy(
|
||||
TemporaryTable entityTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( entityTable, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeInsert(
|
||||
SqmInsertStatement<?> sqmInsertStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedInsertHandler(
|
||||
sqmInsertStatement,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
// generally a global temp table should already track a Connection-specific uid,
|
||||
// but just in case a particular env needs it...
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
||||
/**
|
||||
* Strategy based on ANSI SQL's definition of a "global temporary table".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GlobalTemporaryTableMutationStrategy extends GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrategy {
|
||||
|
||||
public GlobalTemporaryTableMutationStrategy(
|
||||
TemporaryTable idTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( idTable, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement<?> sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
// generally a global temp table should already track a Connection-specific uid,
|
||||
// but just in case a particular env needs it...
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement<?> sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
// generally a global temp table should already track a Connection-specific uid,
|
||||
// but just in case a particular env needs it...
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
}
|
|
@ -4,23 +4,18 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableHelper;
|
||||
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.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -29,15 +24,13 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrategy {
|
||||
public class GlobalTemporaryTableStrategy {
|
||||
private static final Logger log = Logger.getLogger( GlobalTemporaryTableStrategy.class );
|
||||
|
||||
public static final String SHORT_NAME = "global_temporary";
|
||||
public static final String DROP_ID_TABLES = "hibernate.hql.bulk_id_strategy.global_temporary.drop_tables";
|
||||
|
||||
private final IdTable idTable;
|
||||
private final AfterUseAction afterUseAction;
|
||||
private final Supplier<IdTableExporter> idTableExporterAccess;
|
||||
private final TemporaryTable temporaryTable;
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
|
@ -45,61 +38,16 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
private boolean dropIdTables;
|
||||
|
||||
public GlobalTemporaryTableStrategy(
|
||||
IdTable idTable,
|
||||
Supplier<IdTableExporter> idTableExporterAccess,
|
||||
AfterUseAction afterUseAction,
|
||||
TemporaryTable temporaryTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.idTable = idTable;
|
||||
this.idTableExporterAccess = idTableExporterAccess;
|
||||
this.afterUseAction = afterUseAction;
|
||||
this.temporaryTable = temporaryTable;
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
if ( afterUseAction == AfterUseAction.DROP ) {
|
||||
throw new IllegalArgumentException( "Global-temp ID tables cannot use AfterUseAction.DROP : " + idTable.getTableExpression() );
|
||||
if ( sessionFactory.getJdbcServices().getDialect().getTemporaryTableAfterUseAction() == AfterUseAction.DROP ) {
|
||||
throw new IllegalArgumentException( "Global-temp ID tables cannot use AfterUseAction.DROP : " + temporaryTable.getTableExpression() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
idTable,
|
||||
// generally a global temp table should already track a Connection-specific uid,
|
||||
// but just in case a particular env needs it...
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
idTableExporterAccess,
|
||||
BeforeUseAction.CREATE,
|
||||
afterUseAction,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
sessionFactory
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
idTable,
|
||||
// generally a global temp table should already track a Connection-specific uid,
|
||||
// but just in case a particular env needs it...
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
idTableExporterAccess,
|
||||
BeforeUseAction.CREATE,
|
||||
afterUseAction,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
sessionFactory
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(
|
||||
MappingModelCreationProcess mappingModelCreationProcess,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
|
@ -109,11 +57,10 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
|
||||
prepared = true;
|
||||
|
||||
log.debugf( "Creating global-temp ID table : %s", idTable.getTableExpression() );
|
||||
log.debugf( "Creating global-temp ID table : %s", getTemporaryTable().getTableExpression() );
|
||||
|
||||
final IdTableHelper.IdTableCreationWork idTableCreationWork = new IdTableHelper.IdTableCreationWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
final TemporaryTableHelper.TemporaryTableCreationWork temporaryTableCreationWork = new TemporaryTableHelper.TemporaryTableCreationWork(
|
||||
getTemporaryTable(),
|
||||
sessionFactory
|
||||
);
|
||||
Connection connection;
|
||||
|
@ -131,7 +78,7 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
}
|
||||
|
||||
try {
|
||||
idTableCreationWork.execute( connection );
|
||||
temporaryTableCreationWork.execute( connection );
|
||||
final ConfigurationService configService = mappingModelCreationProcess.getCreationContext()
|
||||
.getBootstrapContext()
|
||||
.getServiceRegistry().getService( ConfigurationService.class );
|
||||
|
@ -150,7 +97,6 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
|
@ -160,11 +106,10 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
|
||||
dropIdTables = false;
|
||||
|
||||
log.debugf( "Dropping global-temp ID table : %s", idTable.getTableExpression() );
|
||||
log.debugf( "Dropping global-temp ID table : %s", getTemporaryTable().getTableExpression() );
|
||||
|
||||
final IdTableHelper.IdTableDropWork idTableDropWork = new IdTableHelper.IdTableDropWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
final TemporaryTableHelper.TemporaryTableDropWork temporaryTableDropWork = new TemporaryTableHelper.TemporaryTableDropWork(
|
||||
getTemporaryTable(),
|
||||
sessionFactory
|
||||
);
|
||||
Connection connection;
|
||||
|
@ -173,7 +118,7 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
// assume this comes from org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl
|
||||
log.debugf( "Unable to obtain JDBC connection; unable to drop global-temp ID table : %s", idTable.getTableExpression() );
|
||||
log.debugf( "Unable to obtain JDBC connection; unable to drop global-temp ID table : %s", getTemporaryTable().getTableExpression() );
|
||||
return;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
|
@ -182,7 +127,7 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
}
|
||||
|
||||
try {
|
||||
idTableDropWork.execute( connection );
|
||||
temporaryTableDropWork.execute( connection );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
|
@ -192,4 +137,12 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TemporaryTable getTemporaryTable() {
|
||||
return temporaryTable;
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableColumn;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
import org.hibernate.id.insert.Binder;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.query.results.TableGroupImpl;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.ast.tree.select.SortSpecification;
|
||||
import org.hibernate.sql.ast.tree.update.Assignable;
|
||||
import org.hibernate.sql.ast.tree.update.Assignment;
|
||||
import org.hibernate.sql.ast.tree.update.UpdateStatement;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcInsert;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcUpdate;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class InsertExecutionDelegate implements TableBasedInsertHandler.ExecutionDelegate {
|
||||
private final SqmInsertStatement<?> sqmInsert;
|
||||
private final MultiTableSqmMutationConverter sqmConverter;
|
||||
private final TemporaryTable entityTable;
|
||||
private final Function<SharedSessionContractImplementor, String> sessionUidAccess;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
private final TableGroup updatingTableGroup;
|
||||
private final InsertStatement insertStatement;
|
||||
|
||||
private final EntityMappingType entityDescriptor;
|
||||
|
||||
private final JdbcParameterBindings jdbcParameterBindings;
|
||||
|
||||
private final Map<TableReference, List<Assignment>> assignmentsByTable;
|
||||
private final Map<SqmParameter, MappingModelExpressable> paramTypeResolutions;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
public InsertExecutionDelegate(
|
||||
SqmInsertStatement<?> sqmInsert,
|
||||
MultiTableSqmMutationConverter sqmConverter,
|
||||
TemporaryTable entityTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
DomainParameterXref domainParameterXref,
|
||||
TableGroup insertingTableGroup,
|
||||
Map<String, TableReference> tableReferenceByAlias,
|
||||
List<Assignment> assignments,
|
||||
InsertStatement insertStatement,
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> parameterResolutions,
|
||||
Map<SqmParameter, MappingModelExpressable> paramTypeResolutions,
|
||||
DomainQueryExecutionContext executionContext) {
|
||||
this.sqmInsert = sqmInsert;
|
||||
this.sqmConverter = sqmConverter;
|
||||
this.entityTable = entityTable;
|
||||
this.sessionUidAccess = sessionUidAccess;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
this.updatingTableGroup = insertingTableGroup;
|
||||
this.paramTypeResolutions = paramTypeResolutions;
|
||||
this.insertStatement = insertStatement;
|
||||
|
||||
this.sessionFactory = executionContext.getSession().getFactory();
|
||||
|
||||
final ModelPartContainer updatingModelPart = insertingTableGroup.getModelPart();
|
||||
assert updatingModelPart instanceof EntityMappingType;
|
||||
|
||||
this.entityDescriptor = (EntityMappingType) updatingModelPart;
|
||||
|
||||
this.assignmentsByTable = CollectionHelper.mapOfSize( insertingTableGroup.getTableReferenceJoins().size() + 1 );
|
||||
|
||||
jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
|
||||
executionContext.getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
SqmUtil.generateJdbcParamsXref(
|
||||
domainParameterXref,
|
||||
() -> parameterResolutions
|
||||
),
|
||||
sessionFactory.getDomainModel(),
|
||||
navigablePath -> insertingTableGroup,
|
||||
paramTypeResolutions::get,
|
||||
executionContext.getSession()
|
||||
);
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// segment the assignments by table-reference
|
||||
|
||||
for ( int i = 0; i < assignments.size(); i++ ) {
|
||||
final Assignment assignment = assignments.get( i );
|
||||
final Assignable assignable = assignment.getAssignable();
|
||||
final List<ColumnReference> assignmentColumnRefs = assignable.getColumnReferences();
|
||||
|
||||
TableReference assignmentTableReference = null;
|
||||
|
||||
for ( int c = 0; c < assignmentColumnRefs.size(); c++ ) {
|
||||
final ColumnReference columnReference = assignmentColumnRefs.get( c );
|
||||
final TableReference tableReference = resolveTableReference(
|
||||
columnReference,
|
||||
insertingTableGroup,
|
||||
tableReferenceByAlias
|
||||
);
|
||||
|
||||
if ( assignmentTableReference != null && assignmentTableReference != tableReference ) {
|
||||
throw new SemanticException( "Assignment referred to columns from multiple tables: " + i );
|
||||
}
|
||||
|
||||
assignmentTableReference = tableReference;
|
||||
}
|
||||
|
||||
assignmentsByTable.computeIfAbsent( assignmentTableReference, k -> new ArrayList<>() )
|
||||
.add( assignment );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
ExecuteWithTemporaryTableHelper.performBeforeTemporaryTableUseActions(
|
||||
entityTable,
|
||||
executionContext
|
||||
);
|
||||
|
||||
try {
|
||||
final int rows = ExecuteWithTemporaryTableHelper.saveIntoTemporaryTable(
|
||||
insertStatement,
|
||||
jdbcParameterBindings,
|
||||
executionContext
|
||||
);
|
||||
|
||||
if ( rows != 0 ) {
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister) entityDescriptor.getEntityPersister();
|
||||
final int tableSpan = persister.getTableSpan();
|
||||
insertRootTable( persister.getTableName( 0 ), rows, persister.getKeyColumns( 0 ), executionContext );
|
||||
|
||||
for ( int i = 1; i < tableSpan; i++ ) {
|
||||
insertTable(
|
||||
persister.getTableName( i ),
|
||||
persister.getKeyColumns( i ),
|
||||
persister.isNullableTable( i ),
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
finally {
|
||||
ExecuteWithTemporaryTableHelper.performAfterTemporaryTableUseActions(
|
||||
entityTable,
|
||||
sessionUidAccess,
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private TableReference resolveTableReference(
|
||||
ColumnReference columnReference,
|
||||
TableGroup updatingTableGroup,
|
||||
Map<String, TableReference> tableReferenceByAlias) {
|
||||
if ( columnReference.getQualifier() == null ) {
|
||||
// This happens only for the special row_number column
|
||||
return null;
|
||||
}
|
||||
final TableReference tableReferenceByQualifier = tableReferenceByAlias.get( columnReference.getQualifier() );
|
||||
if ( tableReferenceByQualifier != null ) {
|
||||
return tableReferenceByQualifier;
|
||||
}
|
||||
|
||||
throw new SemanticException( "Assignment referred to column of a joined association: " + columnReference );
|
||||
}
|
||||
|
||||
private TableReference resolveUnionTableReference(TableReference tableReference, String tableExpression) {
|
||||
if ( tableReference instanceof UnionTableReference ) {
|
||||
return new TableReference(
|
||||
tableExpression,
|
||||
tableReference.getIdentificationVariable(),
|
||||
tableReference.isOptional(),
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
else {
|
||||
return tableReference;
|
||||
}
|
||||
}
|
||||
|
||||
private void insertRootTable(
|
||||
String tableExpression,
|
||||
int rows,
|
||||
String[] keyColumns,
|
||||
ExecutionContext executionContext) {
|
||||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister().getIdentifierGenerator();
|
||||
final List<Assignment> assignments = assignmentsByTable.get( updatingTableReference );
|
||||
if ( ( assignments == null || assignments.isEmpty() ) && !( identifierGenerator instanceof PostInsertIdentifierGenerator ) ) {
|
||||
throw new IllegalStateException( "There must be at least a single root table assignment" );
|
||||
}
|
||||
|
||||
final TableReference dmlTableReference = resolveUnionTableReference( updatingTableReference, tableExpression );
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create the SQL AST and convert it into a JdbcOperation
|
||||
final QuerySpec querySpec = new QuerySpec( true );
|
||||
final TableGroupImpl temporaryTableGroup = new TableGroupImpl(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
null,
|
||||
new TableReference(
|
||||
insertStatement.getTargetTable().getTableExpression(),
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
false,
|
||||
sessionFactory
|
||||
),
|
||||
entityDescriptor,
|
||||
null
|
||||
);
|
||||
querySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final InsertStatement insertStatement = new InsertStatement( dmlTableReference );
|
||||
insertStatement.setSourceSelectStatement( querySpec );
|
||||
for ( Assignment assignment : assignments ) {
|
||||
insertStatement.addTargetColumnReferences( assignment.getAssignable().getColumnReferences() );
|
||||
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
columnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
columnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
final Map<Object, Object> entityTableToRootIdentity;
|
||||
if ( identifierGenerator instanceof PostInsertIdentifierGenerator ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final QuerySpec idSelectQuerySpec = new QuerySpec( true );
|
||||
idSelectQuerySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final ColumnReference columnReference = new ColumnReference(
|
||||
(String) null,
|
||||
TemporaryTable.ENTITY_TABLE_IDENTITY_COLUMN,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
identifierMapping.getJdbcMapping(),
|
||||
sessionFactory
|
||||
);
|
||||
idSelectQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, columnReference ) );
|
||||
idSelectQuerySpec.addSortSpecification(
|
||||
new SortSpecification(
|
||||
columnReference,
|
||||
null,
|
||||
SortOrder.ASCENDING
|
||||
)
|
||||
);
|
||||
final SelectStatement selectStatement = new SelectStatement(
|
||||
idSelectQuerySpec,
|
||||
Collections.singletonList(
|
||||
new BasicFetch<>(
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
identifierMapping,
|
||||
null,
|
||||
FetchTiming.IMMEDIATE,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
final JdbcSelect jdbcSelect = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildSelectTranslator( sessionFactory, selectStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
final List<Object> list = jdbcServices.getJdbcSelectExecutor().list(
|
||||
jdbcSelect,
|
||||
JdbcParameterBindings.NO_BINDINGS,
|
||||
executionContext,
|
||||
null,
|
||||
ListResultsConsumer.UniqueSemantic.NONE
|
||||
);
|
||||
entityTableToRootIdentity = new LinkedHashMap<>( list.size() );
|
||||
for ( Object o : list ) {
|
||||
entityTableToRootIdentity.put( o, null );
|
||||
}
|
||||
|
||||
querySpec.applyPredicate(
|
||||
new ComparisonPredicate(
|
||||
columnReference,
|
||||
ComparisonOperator.EQUAL,
|
||||
new JdbcParameterImpl( identifierMapping.getJdbcMapping() )
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
entityTableToRootIdentity = null;
|
||||
if ( identifierGenerator instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
// If the generator uses an optimizer, we have to generate the identifiers for the new rows
|
||||
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
|
||||
final JdbcParameter rowNumber = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final JdbcParameter rootIdentity = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final List<Assignment> temporaryTableAssignments = new ArrayList<>( 1 );
|
||||
final ColumnReference idColumnReference = new ColumnReference(
|
||||
(String) null,
|
||||
identifierMapping,
|
||||
sessionFactory
|
||||
);
|
||||
temporaryTableAssignments.add(
|
||||
new Assignment(
|
||||
idColumnReference,
|
||||
rootIdentity
|
||||
)
|
||||
);
|
||||
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(
|
||||
entityTable.getColumns().size() - 1
|
||||
);
|
||||
final UpdateStatement updateStatement = new UpdateStatement(
|
||||
temporaryTableGroup.getPrimaryTableReference(),
|
||||
temporaryTableAssignments,
|
||||
new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
rowNumberColumn.getColumnName(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
rowNumberColumn.getJdbcMapping(),
|
||||
sessionFactory
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
rowNumber
|
||||
)
|
||||
);
|
||||
|
||||
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildUpdateTranslator( sessionFactory, updateStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl( 2 );
|
||||
|
||||
for ( int i = 0; i < rows; i++ ) {
|
||||
updateBindings.addBinding(
|
||||
rowNumber,
|
||||
new JdbcParameterBindingImpl(
|
||||
rowNumberColumn.getJdbcMapping(),
|
||||
i + 1
|
||||
)
|
||||
);
|
||||
updateBindings.addBinding(
|
||||
rootIdentity,
|
||||
new JdbcParameterBindingImpl(
|
||||
identifierMapping.getJdbcMapping(),
|
||||
identifierGenerator.generate(
|
||||
executionContext.getSession(),
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcUpdate,
|
||||
updateBindings,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
|
||||
// Finally, we also have to add the id to the insertion targets if it's not already there
|
||||
if ( insertStatement.getTargetColumnReferences()
|
||||
.stream()
|
||||
.noneMatch( c -> keyColumns[0].equals( c.getColumnExpression() ) ) ) {
|
||||
insertStatement.addTargetColumnReferences(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
keyColumns[0],
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
identifierMapping.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
idColumnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
idColumnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final JdbcInsert jdbcInsert = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildInsertTranslator( sessionFactory, insertStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
|
||||
if ( identifierGenerator instanceof PostInsertIdentifierGenerator ) {
|
||||
final PostInsertIdentifierGenerator generator = (PostInsertIdentifierGenerator) identifierGenerator;
|
||||
final boolean generatedKeysEnabled = sessionFactory.getSessionFactoryOptions().isGetGeneratedKeysEnabled();
|
||||
final InsertGeneratedIdentifierDelegate identifierDelegate = generator.getInsertGeneratedIdentifierDelegate(
|
||||
(PostInsertIdentityPersister) entityDescriptor.getEntityPersister(),
|
||||
jdbcServices.getDialect(),
|
||||
generatedKeysEnabled
|
||||
);
|
||||
final String finalSql = identifierDelegate.prepareIdentifierGeneratingInsert( jdbcInsert.getSql() );
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final ValueBinder jdbcValueBinder = identifierMapping.getJdbcMapping().getJdbcValueBinder();
|
||||
for ( Map.Entry<Object, Object> entry : entityTableToRootIdentity.entrySet() ) {
|
||||
final Object rootIdentity = identifierDelegate.performInsert(
|
||||
finalSql,
|
||||
executionContext.getSession(),
|
||||
new Binder() {
|
||||
@Override
|
||||
public void bindValues(PreparedStatement ps) throws SQLException {
|
||||
jdbcValueBinder.bind( ps, entry.getKey(), 1, executionContext.getSession() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getEntity() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
entry.setValue( rootIdentity );
|
||||
}
|
||||
|
||||
final JdbcParameter entityIdentity = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final JdbcParameter rootIdentity = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final List<Assignment> temporaryTableAssignments = new ArrayList<>( 1 );
|
||||
temporaryTableAssignments.add(
|
||||
new Assignment(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
identifierMapping,
|
||||
sessionFactory
|
||||
),
|
||||
rootIdentity
|
||||
)
|
||||
);
|
||||
final UpdateStatement updateStatement = new UpdateStatement(
|
||||
temporaryTableGroup.getPrimaryTableReference(),
|
||||
temporaryTableAssignments,
|
||||
new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
TemporaryTable.ENTITY_TABLE_IDENTITY_COLUMN,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
identifierMapping.getJdbcMapping(),
|
||||
sessionFactory
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
entityIdentity
|
||||
)
|
||||
);
|
||||
|
||||
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildUpdateTranslator( sessionFactory, updateStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl( 2 );
|
||||
|
||||
for ( Map.Entry<Object, Object> entry : entityTableToRootIdentity.entrySet() ) {
|
||||
updateBindings.addBinding( entityIdentity, new JdbcParameterBindingImpl( identifierMapping.getJdbcMapping(), entry.getKey() ) );
|
||||
updateBindings.addBinding( rootIdentity, new JdbcParameterBindingImpl( identifierMapping.getJdbcMapping(), entry.getValue() ) );
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcUpdate,
|
||||
updateBindings,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcInsert,
|
||||
JdbcParameterBindings.NO_BINDINGS,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertTable(
|
||||
String tableExpression,
|
||||
String[] keyColumns,
|
||||
boolean nullableTable,
|
||||
ExecutionContext executionContext) {
|
||||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
final List<Assignment> assignments = assignmentsByTable.get( updatingTableReference );
|
||||
if ( nullableTable && ( assignments == null || assignments.isEmpty() ) ) {
|
||||
// no assignments for this table - skip it
|
||||
return;
|
||||
}
|
||||
final TableReference dmlTargetTableReference = resolveUnionTableReference( updatingTableReference, tableExpression );
|
||||
|
||||
final QuerySpec querySpec = new QuerySpec( true );
|
||||
final TableGroupImpl temporaryTableGroup = new TableGroupImpl(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
null,
|
||||
new TableReference(
|
||||
insertStatement.getTargetTable().getTableExpression(),
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
false,
|
||||
sessionFactory
|
||||
),
|
||||
entityDescriptor,
|
||||
null
|
||||
);
|
||||
querySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final InsertStatement insertStatement = new InsertStatement( dmlTargetTableReference );
|
||||
insertStatement.setSourceSelectStatement( querySpec );
|
||||
if ( assignments != null && !assignments.isEmpty() ) {
|
||||
for ( Assignment assignment : assignments ) {
|
||||
insertStatement.addTargetColumnReferences( assignment.getAssignable().getColumnReferences() );
|
||||
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
columnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
columnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
final String targetKeyColumnName = keyColumns[0];
|
||||
final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityDescriptor.getEntityPersister();
|
||||
final IdentifierGenerator identifierGenerator = entityPersister.getIdentifierGenerator();
|
||||
final boolean needsKeyInsert;
|
||||
if ( identifierGenerator instanceof PostInsertIdentifierGenerator ) {
|
||||
needsKeyInsert = true;
|
||||
}
|
||||
else if ( identifierGenerator instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
// If the generator uses an optimizer, we have to generate the identifiers for the new rows
|
||||
needsKeyInsert = optimizer != null && optimizer.getIncrementSize() > 1;
|
||||
}
|
||||
else {
|
||||
needsKeyInsert = false;
|
||||
}
|
||||
if ( needsKeyInsert && insertStatement.getTargetColumnReferences()
|
||||
.stream()
|
||||
.noneMatch( c -> targetKeyColumnName.equals( c.getColumnExpression() ) ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
insertStatement.addTargetColumnReferences(
|
||||
new ColumnReference(
|
||||
dmlTargetTableReference.getIdentificationVariable(),
|
||||
targetKeyColumnName,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
identifierMapping.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
identifierMapping,
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
final JdbcInsert jdbcInsert = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildInsertTranslator( sessionFactory, insertStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcInsert,
|
||||
JdbcParameterBindings.NO_BINDINGS,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
|
||||
/**
|
||||
* Strategy based on ANSI SQL's definition of a "local temporary table" (local to each db session).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalTemporaryTableInsertStrategy extends LocalTemporaryTableStrategy implements SqmMultiTableInsertStrategy {
|
||||
|
||||
public LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable entityTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( entityTable, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeInsert(
|
||||
SqmInsertStatement<?> sqmInsertStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedInsertHandler(
|
||||
sqmInsertStatement,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
session -> {
|
||||
throw new UnsupportedOperationException( "Unexpected call to access Session uid" );
|
||||
},
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
||||
/**
|
||||
* Strategy based on ANSI SQL's definition of a "local temporary table" (local to each db session).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LocalTemporaryTableMutationStrategy extends LocalTemporaryTableStrategy implements SqmMultiTableMutationStrategy {
|
||||
|
||||
public LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable idTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( idTable, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement<?> sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
session -> {
|
||||
throw new UnsupportedOperationException( "Unexpected call to access Session uid" );
|
||||
},
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement<?> sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
session -> {
|
||||
throw new UnsupportedOperationException( "Unexpected call to access Session uid" );
|
||||
},
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableHelper;
|
||||
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.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
|
||||
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 LocalTemporaryTableStrategy {
|
||||
private static final Logger log = Logger.getLogger( LocalTemporaryTableStrategy.class );
|
||||
|
||||
public static final String SHORT_NAME = "local_temporary";
|
||||
public static final String DROP_ID_TABLES = "hibernate.hql.bulk_id_strategy.local_temporary.drop_tables";
|
||||
|
||||
private final TemporaryTable temporaryTable;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private boolean dropIdTables;
|
||||
|
||||
public LocalTemporaryTableStrategy(
|
||||
TemporaryTable temporaryTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.temporaryTable = temporaryTable;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
public void prepare(
|
||||
MappingModelCreationProcess mappingModelCreationProcess,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
final ConfigurationService configService = mappingModelCreationProcess.getCreationContext()
|
||||
.getBootstrapContext()
|
||||
.getServiceRegistry().getService( ConfigurationService.class );
|
||||
this.dropIdTables = configService.getSetting(
|
||||
DROP_ID_TABLES,
|
||||
StandardConverters.BOOLEAN,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public void release(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
if ( !dropIdTables ) {
|
||||
return;
|
||||
}
|
||||
|
||||
dropIdTables = false;
|
||||
|
||||
final TemporaryTable temporaryTable = getTemporaryTable();
|
||||
log.debugf( "Dropping local-temp ID table : %s", temporaryTable.getTableExpression() );
|
||||
|
||||
final TemporaryTableHelper.TemporaryTableDropWork temporaryTableDropWork = new TemporaryTableHelper.TemporaryTableDropWork(
|
||||
temporaryTable,
|
||||
sessionFactory
|
||||
);
|
||||
Connection connection;
|
||||
try {
|
||||
connection = connectionAccess.obtainConnection();
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
// assume this comes from org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl
|
||||
log.debugf( "Unable to obtain JDBC connection; unable to drop local-temp ID table : %s", temporaryTable.getTableExpression() );
|
||||
return;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error( "Unable obtain JDBC Connection", e );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
temporaryTableDropWork.execute( connection );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connectionAccess.releaseConnection( connection );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TemporaryTable getTemporaryTable() {
|
||||
return temporaryTable;
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
|
||||
/**
|
||||
* 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 PersistentTableInsertStrategy extends PersistentTableStrategy implements SqmMultiTableInsertStrategy {
|
||||
|
||||
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";
|
||||
|
||||
public PersistentTableInsertStrategy(
|
||||
TemporaryTable entityTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( entityTable, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeInsert(
|
||||
SqmInsertStatement<?> sqmInsertStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedInsertHandler(
|
||||
sqmInsertStatement,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
||||
/**
|
||||
* 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 PersistentTableMutationStrategy extends PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
||||
|
||||
public PersistentTableMutationStrategy(
|
||||
TemporaryTable idTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( idTable, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement<?> sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement<?> sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
getTemporaryTable(),
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
getSessionFactory()
|
||||
).execute( context );
|
||||
}
|
||||
}
|
|
@ -4,21 +4,16 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableHelper;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -29,7 +24,7 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
||||
public abstract class PersistentTableStrategy {
|
||||
private static final Logger log = Logger.getLogger( PersistentTableStrategy.class );
|
||||
|
||||
public static final String SHORT_NAME = "persistent";
|
||||
|
@ -39,9 +34,7 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
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 final IdTable idTable;
|
||||
private final AfterUseAction afterUseAction;
|
||||
private final Supplier<IdTableExporter> idTableExporterAccess;
|
||||
private final TemporaryTable temporaryTable;
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
|
@ -50,57 +43,16 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
private boolean released;
|
||||
|
||||
public PersistentTableStrategy(
|
||||
IdTable idTable,
|
||||
AfterUseAction afterUseAction,
|
||||
Supplier<IdTableExporter> idTableExporterAccess,
|
||||
TemporaryTable temporaryTable,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.idTable = idTable;
|
||||
this.afterUseAction = afterUseAction;
|
||||
this.idTableExporterAccess = idTableExporterAccess;
|
||||
this.temporaryTable = temporaryTable;
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
if ( afterUseAction == AfterUseAction.DROP ) {
|
||||
throw new IllegalArgumentException( "Persistent ID tables cannot use AfterUseAction.DROP : " + idTable.getTableExpression() );
|
||||
if ( sessionFactory.getJdbcServices().getDialect().getTemporaryTableAfterUseAction() == AfterUseAction.DROP ) {
|
||||
throw new IllegalArgumentException( "Persistent ID tables cannot use AfterUseAction.DROP : " + temporaryTable.getTableExpression() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
idTable,
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
idTableExporterAccess,
|
||||
BeforeUseAction.CREATE,
|
||||
afterUseAction,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
sessionFactory
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
idTable,
|
||||
session -> session.getSessionIdentifier().toString(),
|
||||
idTableExporterAccess,
|
||||
BeforeUseAction.CREATE,
|
||||
afterUseAction,
|
||||
TempTableDdlTransactionHandling.NONE,
|
||||
sessionFactory
|
||||
).execute( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(
|
||||
MappingModelCreationProcess mappingModelCreationProcess,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
|
@ -110,11 +62,10 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
|
||||
prepared = true;
|
||||
|
||||
log.debugf( "Creating persistent ID table : %s", idTable.getTableExpression() );
|
||||
log.debugf( "Creating persistent ID table : %s", getTemporaryTable().getTableExpression() );
|
||||
|
||||
final IdTableHelper.IdTableCreationWork idTableCreationWork = new IdTableHelper.IdTableCreationWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
final TemporaryTableHelper.TemporaryTableCreationWork temporaryTableCreationWork = new TemporaryTableHelper.TemporaryTableCreationWork(
|
||||
getTemporaryTable(),
|
||||
sessionFactory
|
||||
);
|
||||
Connection connection;
|
||||
|
@ -132,7 +83,7 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
}
|
||||
|
||||
try {
|
||||
idTableCreationWork.execute( connection );
|
||||
temporaryTableCreationWork.execute( connection );
|
||||
created = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -148,7 +99,6 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
JdbcConnectionAccess connectionAccess) {
|
||||
|
@ -162,12 +112,11 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
return;
|
||||
}
|
||||
|
||||
final TemporaryTable temporaryTable = getTemporaryTable();
|
||||
log.debugf( "Dropping persistent ID table : %s", temporaryTable.getTableExpression() );
|
||||
|
||||
log.debugf( "Dropping persistent ID table : %s", idTable.getTableExpression() );
|
||||
|
||||
final IdTableHelper.IdTableDropWork idTableDropWork = new IdTableHelper.IdTableDropWork(
|
||||
idTable,
|
||||
idTableExporterAccess.get(),
|
||||
final TemporaryTableHelper.TemporaryTableDropWork temporaryTableDropWork = new TemporaryTableHelper.TemporaryTableDropWork(
|
||||
temporaryTable,
|
||||
sessionFactory
|
||||
);
|
||||
Connection connection;
|
||||
|
@ -176,7 +125,7 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
// assume this comes from org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl
|
||||
log.debugf( "Unable to obtain JDBC connection; unable to drop persistent ID table : %s", idTable.getTableExpression() );
|
||||
log.debugf( "Unable to obtain JDBC connection; unable to drop persistent ID table : %s", temporaryTable.getTableExpression() );
|
||||
return;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
|
@ -185,7 +134,7 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
}
|
||||
|
||||
try {
|
||||
idTableDropWork.execute( connection );
|
||||
temporaryTableDropWork.execute( connection );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
|
@ -195,4 +144,12 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TemporaryTable getTemporaryTable() {
|
||||
return temporaryTable;
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -16,7 +16,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -69,29 +69,20 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
private static final Logger log = Logger.getLogger( RestrictedDeleteExecutionDelegate.class );
|
||||
|
||||
private final EntityMappingType entityDescriptor;
|
||||
private final IdTable idTable;
|
||||
private final TemporaryTable idTable;
|
||||
private final SqmDeleteStatement<?> sqmDelete;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private final BeforeUseAction beforeUseAction;
|
||||
private final AfterUseAction afterUseAction;
|
||||
private final TempTableDdlTransactionHandling ddlTransactionHandling;
|
||||
private final Supplier<IdTableExporter> idTableExporterAccess;
|
||||
|
||||
private final Function<SharedSessionContractImplementor,String> sessionUidAccess;
|
||||
private final MultiTableSqmMutationConverter converter;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public RestrictedDeleteExecutionDelegate(
|
||||
EntityMappingType entityDescriptor,
|
||||
IdTable idTable,
|
||||
TemporaryTable idTable,
|
||||
SqmDeleteStatement<?> sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
BeforeUseAction beforeUseAction,
|
||||
AfterUseAction afterUseAction,
|
||||
TempTableDdlTransactionHandling ddlTransactionHandling,
|
||||
Supplier<IdTableExporter> idTableExporterAccess,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
QueryOptions queryOptions,
|
||||
LoadQueryInfluencers loadQueryInfluencers,
|
||||
|
@ -101,10 +92,6 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
this.idTable = idTable;
|
||||
this.sqmDelete = sqmDelete;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
this.beforeUseAction = beforeUseAction;
|
||||
this.afterUseAction = afterUseAction;
|
||||
this.ddlTransactionHandling = ddlTransactionHandling;
|
||||
this.idTableExporterAccess = idTableExporterAccess;
|
||||
this.sessionUidAccess = sessionUidAccess;
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.converter = new MultiTableSqmMutationConverter(
|
||||
|
@ -489,11 +476,8 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
executionContext.getSession()
|
||||
);
|
||||
|
||||
ExecuteWithIdTableHelper.performBeforeIdTableUseActions(
|
||||
beforeUseAction,
|
||||
ExecuteWithTemporaryTableHelper.performBeforeTemporaryTableUseActions(
|
||||
idTable,
|
||||
idTableExporterAccess,
|
||||
ddlTransactionHandling,
|
||||
executionContext
|
||||
);
|
||||
|
||||
|
@ -501,11 +485,8 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
return executeUsingIdTable( predicate, executionContext, jdbcParameterBindings );
|
||||
}
|
||||
finally {
|
||||
ExecuteWithIdTableHelper.performAfterIdTableUseActions(
|
||||
afterUseAction,
|
||||
ExecuteWithTemporaryTableHelper.performAfterTemporaryTableUseActions(
|
||||
idTable,
|
||||
idTableExporterAccess,
|
||||
ddlTransactionHandling,
|
||||
sessionUidAccess,
|
||||
executionContext
|
||||
);
|
||||
|
@ -516,7 +497,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
Predicate predicate,
|
||||
ExecutionContext executionContext,
|
||||
JdbcParameterBindings jdbcParameterBindings) {
|
||||
final int rows = ExecuteWithIdTableHelper.saveMatchingIdsIntoIdTable(
|
||||
final int rows = ExecuteWithTemporaryTableHelper.saveMatchingIdsIntoIdTable(
|
||||
converter,
|
||||
predicate,
|
||||
idTable,
|
||||
|
@ -525,7 +506,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
executionContext
|
||||
);
|
||||
|
||||
final QuerySpec idTableIdentifierSubQuery = ExecuteWithIdTableHelper.createIdTableSelectQuerySpec(
|
||||
final QuerySpec idTableIdentifierSubQuery = ExecuteWithTemporaryTableHelper.createIdTableSelectQuerySpec(
|
||||
idTable,
|
||||
sessionUidAccess,
|
||||
entityDescriptor,
|
||||
|
@ -541,7 +522,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
idTableFkSubQuery = idTableIdentifierSubQuery;
|
||||
}
|
||||
else {
|
||||
idTableFkSubQuery = ExecuteWithIdTableHelper.createIdTableSelectQuerySpec(
|
||||
idTableFkSubQuery = ExecuteWithTemporaryTableHelper.createIdTableSelectQuerySpec(
|
||||
idTable,
|
||||
fkDescriptor.getTargetPart(),
|
||||
sessionUidAccess,
|
|
@ -4,12 +4,11 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal.idtable;
|
||||
package org.hibernate.query.sqm.mutation.internal.temptable;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
|
@ -32,37 +31,24 @@ public class TableBasedDeleteHandler
|
|||
int execute(DomainQueryExecutionContext executionContext);
|
||||
}
|
||||
|
||||
private final IdTable idTable;
|
||||
private final TempTableDdlTransactionHandling ddlTransactionHandling;
|
||||
private final BeforeUseAction beforeUseAction;
|
||||
private final AfterUseAction afterUseAction;
|
||||
private final TemporaryTable idTable;
|
||||
private final Function<SharedSessionContractImplementor,String> sessionUidAccess;
|
||||
private final Supplier<IdTableExporter> exporterSupplier;
|
||||
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
|
||||
|
||||
public TableBasedDeleteHandler(
|
||||
SqmDeleteStatement sqmDeleteStatement,
|
||||
SqmDeleteStatement<?> sqmDeleteStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
IdTable idTable,
|
||||
Function<SharedSessionContractImplementor,
|
||||
String> sessionUidAccess,
|
||||
Supplier<IdTableExporter> exporterSupplier,
|
||||
BeforeUseAction beforeUseAction,
|
||||
AfterUseAction afterUseAction,
|
||||
TempTableDdlTransactionHandling ddlTransactionHandling,
|
||||
TemporaryTable idTable,
|
||||
Function<SharedSessionContractImplementor, String> sessionUidAccess,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( sqmDeleteStatement, sessionFactory );
|
||||
this.idTable = idTable;
|
||||
this.ddlTransactionHandling = ddlTransactionHandling;
|
||||
this.beforeUseAction = beforeUseAction;
|
||||
this.afterUseAction = afterUseAction;
|
||||
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
|
||||
this.sessionUidAccess = sessionUidAccess;
|
||||
this.exporterSupplier = exporterSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,10 +68,6 @@ public class TableBasedDeleteHandler
|
|||
idTable,
|
||||
getSqmDeleteOrUpdateStatement(),
|
||||
domainParameterXref,
|
||||
beforeUseAction,
|
||||
afterUseAction,
|
||||
ddlTransactionHandling,
|
||||
exporterSupplier,
|
||||
sessionUidAccess,
|
||||
executionContext.getQueryOptions(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue