Fix collection table cleanup issues for all strategies

This commit is contained in:
Christian Beikov 2021-10-22 16:27:33 +02:00
parent fa3101c29e
commit 756afb8788
23 changed files with 436 additions and 107 deletions

View File

@ -582,7 +582,7 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) { BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
visitAttributeMappings( visitAttributeMappings(
attributeMapping -> attributeMapping ->
ManagedMappingType.super.applySqlSelections( attributeMapping.applySqlSelections(
navigablePath, navigablePath,
tableGroup, tableGroup,
creationState, creationState,
@ -742,7 +742,7 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
} }
@Override @Override
public void visitAttributeMappings(Consumer<AttributeMapping> action) { public void visitAttributeMappings(Consumer<? super AttributeMapping> action) {
attributeMappings.forEach( action ); attributeMappings.forEach( action );
} }

View File

@ -209,7 +209,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
@Override @Override
default void visitAttributeMappings(Consumer<AttributeMapping> action) { default void visitAttributeMappings(Consumer<? super AttributeMapping> action) {
getAttributeMappings().forEach( action ); getAttributeMappings().forEach( action );
} }

View File

@ -47,7 +47,7 @@ public interface ManagedMappingType extends MappingType, FetchableContainer {
/** /**
* Visit attributes defined on this class and any supers * Visit attributes defined on this class and any supers
*/ */
void visitAttributeMappings(Consumer<AttributeMapping> action); void visitAttributeMappings(Consumer<? super AttributeMapping> action);
/** /**
* Visit attributes defined on this class and any supers * Visit attributes defined on this class and any supers

View File

@ -14,6 +14,7 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableGroup;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey; import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
@ -25,6 +26,14 @@ public class MappingModelHelper {
ModelPart modelPart, ModelPart modelPart,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
return buildColumnReferenceExpression( null, modelPart, sqlExpressionResolver, sessionFactory );
}
public static Expression buildColumnReferenceExpression(
TableGroup tableGroup,
ModelPart modelPart,
SqlExpressionResolver sqlExpressionResolver,
SessionFactoryImplementor sessionFactory) {
final int jdbcTypeCount = modelPart.getJdbcTypeCount(); final int jdbcTypeCount = modelPart.getJdbcTypeCount();
if ( modelPart instanceof EmbeddableValuedModelPart ) { if ( modelPart instanceof EmbeddableValuedModelPart ) {
@ -32,9 +41,16 @@ public class MappingModelHelper {
modelPart.forEachSelectable( modelPart.forEachSelectable(
(columnIndex, selection) -> { (columnIndex, selection) -> {
final ColumnReference colRef; final ColumnReference colRef;
final String qualifier;
if ( tableGroup == null ) {
qualifier = selection.getContainingTableExpression();
}
else {
qualifier = tableGroup.getTableReference( selection.getContainingTableExpression() ).getIdentificationVariable();
}
if ( sqlExpressionResolver == null ) { if ( sqlExpressionResolver == null ) {
colRef = new ColumnReference( colRef = new ColumnReference(
selection.getContainingTableExpression(), qualifier,
selection, selection,
sessionFactory sessionFactory
); );
@ -43,7 +59,7 @@ public class MappingModelHelper {
colRef = (ColumnReference) sqlExpressionResolver.resolveSqlExpression( colRef = (ColumnReference) sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey( selection.getContainingTableExpression(), selection.getSelectionExpression() ), createColumnReferenceKey( selection.getContainingTableExpression(), selection.getSelectionExpression() ),
sqlAstProcessingState -> new ColumnReference( sqlAstProcessingState -> new ColumnReference(
selection.getContainingTableExpression(), qualifier,
selection, selection,
sessionFactory sessionFactory
) )
@ -57,9 +73,16 @@ public class MappingModelHelper {
else { else {
assert modelPart instanceof BasicValuedModelPart; assert modelPart instanceof BasicValuedModelPart;
final BasicValuedModelPart basicPart = (BasicValuedModelPart) modelPart; final BasicValuedModelPart basicPart = (BasicValuedModelPart) modelPart;
final String qualifier;
if ( tableGroup == null ) {
qualifier = basicPart.getContainingTableExpression();
}
else {
qualifier = tableGroup.getTableReference( basicPart.getContainingTableExpression() ).getIdentificationVariable();
}
if ( sqlExpressionResolver == null ) { if ( sqlExpressionResolver == null ) {
return new ColumnReference( return new ColumnReference(
basicPart.getContainingTableExpression(), qualifier,
basicPart, basicPart,
sessionFactory sessionFactory
); );
@ -68,7 +91,7 @@ public class MappingModelHelper {
return sqlExpressionResolver.resolveSqlExpression( return sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey( basicPart.getContainingTableExpression(), basicPart.getSelectionExpression() ), createColumnReferenceKey( basicPart.getContainingTableExpression(), basicPart.getSelectionExpression() ),
sqlAstProcessingState -> new ColumnReference( sqlAstProcessingState -> new ColumnReference(
basicPart.getContainingTableExpression(), qualifier,
basicPart, basicPart,
sessionFactory sessionFactory
) )

View File

@ -7,6 +7,7 @@
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.Locale; import java.util.Locale;
import java.util.function.BiConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchStyle;
@ -212,6 +213,18 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
resolveSqlSelection( navigablePath, tableGroup, true, creationState ); resolveSqlSelection( navigablePath, tableGroup, true, creationState );
} }
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
selectionConsumer.accept(
resolveSqlSelection( navigablePath, tableGroup, true, creationState ),
getJdbcMapping()
);
}
private SqlSelection resolveSqlSelection( private SqlSelection resolveSqlSelection(
NavigablePath navigablePath, NavigablePath navigablePath,
TableGroup tableGroup, TableGroup tableGroup,

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping.internal;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
@ -19,9 +20,14 @@ import org.hibernate.mapping.Property;
import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping; import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.type.ComponentType; import org.hibernate.type.ComponentType;
/** /**
@ -133,6 +139,32 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
} }
} }
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
for ( int i = 0; i < idAttributeMappings.size(); i++ ) {
idAttributeMappings.get( i ).applySqlSelections( navigablePath, tableGroup, creationState );
}
}
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
for ( int i = 0; i < idAttributeMappings.size(); i++ ) {
idAttributeMappings.get( i ).applySqlSelections(
navigablePath,
tableGroup,
creationState,
selectionConsumer
);
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EmbeddableValuedFetchable // EmbeddableValuedFetchable

View File

@ -10,6 +10,7 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.LockMode; import org.hibernate.LockMode;
@ -50,6 +51,7 @@ import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.LazyTableGroup; import org.hibernate.sql.ast.tree.from.LazyTableGroup;
import org.hibernate.sql.ast.tree.from.StandardTableGroup; import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
@ -1157,6 +1159,32 @@ public class ToOneAttributeMapping
} }
} }
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
foreignKeyDescriptor.getKeyPart().applySqlSelections( navigablePath, tableGroup, creationState );
}
}
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
foreignKeyDescriptor.getKeyPart().applySqlSelections(
navigablePath,
tableGroup,
creationState,
selectionConsumer
);
}
}
@Override @Override
public int getJdbcTypeCount() { public int getJdbcTypeCount() {
return foreignKeyDescriptor.getJdbcTypeCount(); return foreignKeyDescriptor.getJdbcTypeCount();

View File

@ -5452,7 +5452,7 @@ public abstract class AbstractEntityPersister
protected ReflectionOptimizer.AccessOptimizer accessOptimizer; protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
@Override @Override
public void visitAttributeMappings(Consumer<AttributeMapping> action) { public void visitAttributeMappings(Consumer<? super AttributeMapping> action) {
attributeMappings.forEach( action ); attributeMappings.forEach( action );
} }
@ -5540,7 +5540,6 @@ public abstract class AbstractEntityPersister
"Entity(" + getEntityName() + ") `staticFetchableList` generator", "Entity(" + getEntityName() + ") `staticFetchableList` generator",
() -> { () -> {
staticFetchableList = new ArrayList<>( attributeMappings.size() ); staticFetchableList = new ArrayList<>( attributeMappings.size() );
visitAttributeMappings( attributeMapping -> staticFetchableList.add( attributeMapping ) );
visitSubTypeAttributeMappings( attributeMapping -> staticFetchableList.add( attributeMapping ) ); visitSubTypeAttributeMappings( attributeMapping -> staticFetchableList.add( attributeMapping ) );
return true; return true;
} }
@ -6352,11 +6351,12 @@ public abstract class AbstractEntityPersister
return; return;
} }
attributeMappings.forEach( fetchableConsumer );
if ( treatTargetType.isTypeOrSuperType( this ) ) { if ( treatTargetType.isTypeOrSuperType( this ) ) {
visitSubTypeAttributeMappings( fetchableConsumer ); visitSubTypeAttributeMappings( fetchableConsumer );
} }
else {
attributeMappings.forEach( fetchableConsumer );
}
} }
protected List<Fetchable> getStaticFetchableList() { protected List<Fetchable> getStaticFetchableList() {
@ -6389,11 +6389,11 @@ public abstract class AbstractEntityPersister
@Override @Override
public void visitSubTypeAttributeMappings(Consumer<? super AttributeMapping> action) { public void visitSubTypeAttributeMappings(Consumer<? super AttributeMapping> action) {
visitAttributeMappings( action );
if ( subclassMappingTypes != null ) { if ( subclassMappingTypes != null ) {
subclassMappingTypes.forEach( subclassMappingTypes.forEach(
(s, subType) -> { (s, subType) -> {
subType.visitDeclaredAttributeMappings( action ); subType.visitDeclaredAttributeMappings( action );
subType.visitSubTypeAttributeMappings( action );
} }
); );
} }

View File

@ -137,26 +137,28 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor(); final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor();
final Expression fkColumnExpression = MappingModelHelper.buildColumnReferenceExpression( final Expression fkColumnExpression = MappingModelHelper.buildColumnReferenceExpression(
fkDescriptor, fkDescriptor.getKeyPart(),
null, null,
factory factory
); );
final QuerySpec matchingIdSubQuery = new QuerySpec( false ); final QuerySpec matchingIdSubQuery = new QuerySpec( false );
final MutatingTableReferenceGroupWrapper tableGroup = new MutatingTableReferenceGroupWrapper(
new NavigablePath( attributeMapping.getRootPathName() ),
attributeMapping,
sqmInterpretation.getSqlAst().getTargetTable()
);
final Expression fkTargetColumnExpression = MappingModelHelper.buildColumnReferenceExpression( final Expression fkTargetColumnExpression = MappingModelHelper.buildColumnReferenceExpression(
fkDescriptor, tableGroup,
fkDescriptor.getTargetPart(),
sqmInterpretation.getSqlExpressionResolver(), sqmInterpretation.getSqlExpressionResolver(),
factory factory
); );
matchingIdSubQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, fkTargetColumnExpression ) ); matchingIdSubQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, fkTargetColumnExpression ) );
matchingIdSubQuery.getFromClause().addRoot( matchingIdSubQuery.getFromClause().addRoot(
new MutatingTableReferenceGroupWrapper( tableGroup
new NavigablePath( attributeMapping.getRootPathName() ),
attributeMapping,
sqmInterpretation.getSqlAst().getTargetTable()
)
); );
matchingIdSubQuery.applyPredicate( sqmInterpretation.getSqlAst().getRestriction() ); matchingIdSubQuery.applyPredicate( sqmInterpretation.getSqlAst().getRestriction() );

View File

@ -18,13 +18,16 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.FilterHelper; import org.hibernate.internal.FilterHelper;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
import org.hibernate.query.spi.DomainQueryExecutionContext; import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter; import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
import org.hibernate.query.sqm.internal.SqmUtil; import org.hibernate.query.sqm.internal.SqmUtil;
import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.SqlAstJoinType;
@ -89,34 +92,29 @@ public class MatchingIdSelectionHelper {
idSelectionQuery.getFromClause().addRoot( mutatingTableGroup ); idSelectionQuery.getFromClause().addRoot( mutatingTableGroup );
final List<DomainResult<?>> domainResults = new ArrayList<>(); final List<DomainResult<?>> domainResults = new ArrayList<>();
sqmConverter.getProcessingStateStack().push(
targetEntityDescriptor.getIdentifierMapping().forEachSelectable( new SqlAstQueryPartProcessingStateImpl(
(position, selection) -> { idSelectionQuery,
final TableReference tableReference = mutatingTableGroup.resolveTableReference( sqmConverter.getCurrentProcessingState(),
mutatingTableGroup.getNavigablePath(), sqmConverter.getSqlAstCreationState(),
selection.getContainingTableExpression() sqmConverter.getCurrentClauseStack()::getCurrent
); )
final Expression expression = sqmConverter.getSqlExpressionResolver().resolveSqlExpression( );
SqlExpressionResolver.createColumnReferenceKey( tableReference, selection.getSelectionExpression() ), targetEntityDescriptor.getIdentifierMapping().applySqlSelections(
sqlAstProcessingState -> new ColumnReference( mutatingTableGroup.getNavigablePath(),
tableReference, mutatingTableGroup,
selection, sqmConverter,
sessionFactory (selection, jdbcMapping) -> {
domainResults.add(
new BasicResult<>(
selection.getValuesArrayPosition(),
null,
jdbcMapping.getJavaTypeDescriptor()
) )
); );
idSelectionQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
position,
position + 1,
expression
)
);
//noinspection unchecked
domainResults.add( new BasicResult( position, null, selection.getJdbcMapping().getJavaTypeDescriptor() ) );
} }
); );
sqmConverter.getProcessingStateStack().pop();
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate( final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
executionContext.getSession().getLoadQueryInfluencers(), executionContext.getSession().getLoadQueryInfluencers(),
@ -237,6 +235,46 @@ public class MatchingIdSelectionHelper {
factory factory
); );
sqmConverter.getProcessingStateStack().push(
new SqlAstQueryPartProcessingStateImpl(
matchingIdSelection.getQuerySpec(),
sqmConverter.getCurrentProcessingState(),
sqmConverter.getSqlAstCreationState(),
sqmConverter.getCurrentClauseStack()::getCurrent
)
);
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 boolean useFkTarget = !( pluralAttribute.getKeyDescriptor()
.getTargetPart() instanceof EntityIdentifierMapping );
if ( useFkTarget ) {
final TableGroup mutatingTableGroup = sqmConverter.getMutatingTableGroup();
pluralAttribute.getKeyDescriptor().getTargetPart().applySqlSelections(
mutatingTableGroup.getNavigablePath(),
mutatingTableGroup,
sqmConverter,
(selection, jdbcMapping) -> {
matchingIdSelection.getDomainResultDescriptors().add(
new BasicResult<>(
selection.getValuesArrayPosition(),
null,
jdbcMapping.getJavaTypeDescriptor()
)
);
}
);
}
}
}
}
);
sqmConverter.getProcessingStateStack().pop();
final JdbcServices jdbcServices = factory.getJdbcServices(); final JdbcServices jdbcServices = factory.getJdbcServices();
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslator<JdbcSelect> sqlAstSelectTranslator = jdbcEnvironment final SqlAstTranslator<JdbcSelect> sqlAstSelectTranslator = jdbcEnvironment

View File

@ -71,7 +71,7 @@ public class SqmMutationStrategyHelper {
return; return;
} }
entityDescriptor.visitAttributeMappings( entityDescriptor.visitSubTypeAttributeMappings(
attributeMapping -> { attributeMapping -> {
if ( attributeMapping instanceof PluralAttributeMapping ) { if ( attributeMapping instanceof PluralAttributeMapping ) {
cleanUpCollectionTable( cleanUpCollectionTable(

View File

@ -20,6 +20,7 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SqlExpressable; import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.query.spi.DomainQueryExecutionContext; import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.DomainParameterXref;
@ -203,6 +204,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
lockOptions.setAliasSpecificLockMode( explicitDmlTargetAlias, LockMode.WRITE ); lockOptions.setAliasSpecificLockMode( explicitDmlTargetAlias, LockMode.WRITE );
final JdbcSelect select = translator.translate( jdbcParameterBindings, executionContext.getQueryOptions() ); final JdbcSelect select = translator.translate( jdbcParameterBindings, executionContext.getQueryOptions() );
lockOptions.setAliasSpecificLockMode( explicitDmlTargetAlias, lockMode ); lockOptions.setAliasSpecificLockMode( explicitDmlTargetAlias, lockMode );
executionContext.getSession().autoFlushIfRequired( select.getAffectedTableNames() );
List<Object> list = jdbcServices.getJdbcSelectExecutor().list( List<Object> list = jdbcServices.getJdbcSelectExecutor().list(
select, select,
jdbcParameterBindings, jdbcParameterBindings,
@ -230,6 +232,14 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
List<? extends Expression> lhsExpressions, List<? extends Expression> lhsExpressions,
CteStatement idSelectCte, CteStatement idSelectCte,
SessionFactoryImplementor factory) { SessionFactoryImplementor factory) {
return createIdSubQueryPredicate( lhsExpressions, idSelectCte, null, factory );
}
protected Predicate createIdSubQueryPredicate(
List<? extends Expression> lhsExpressions,
CteStatement idSelectCte,
ModelPart fkModelPart,
SessionFactoryImplementor factory) {
final TableReference idSelectTableReference = new TableReference( final TableReference idSelectTableReference = new TableReference(
idSelectCte.getCteTable().getTableExpression(), idSelectCte.getCteTable().getTableExpression(),
CTE_TABLE_IDENTIFIER, CTE_TABLE_IDENTIFIER,
@ -238,23 +248,43 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
); );
final Junction predicate = new Junction( Junction.Nature.CONJUNCTION ); final Junction predicate = new Junction( Junction.Nature.CONJUNCTION );
final List<CteColumn> cteColumns = idSelectCte.getCteTable().getCteColumns(); final List<CteColumn> cteColumns = idSelectCte.getCteTable().getCteColumns();
final int size = cteColumns.size(); final int size = lhsExpressions.size();
final QuerySpec subQuery = new QuerySpec( false, 1 ); final QuerySpec subQuery = new QuerySpec( false, 1 );
subQuery.getFromClause().addRoot( new CteTableGroup( idSelectTableReference ) ); subQuery.getFromClause().addRoot( new CteTableGroup( idSelectTableReference ) );
final SelectClause subQuerySelectClause = subQuery.getSelectClause(); final SelectClause subQuerySelectClause = subQuery.getSelectClause();
for ( int i = 0; i < size; i++ ) { if ( fkModelPart == null ) {
final CteColumn cteColumn = cteColumns.get( i ); for ( int i = 0; i < size; i++ ) {
subQuerySelectClause.addSqlSelection( final CteColumn cteColumn = cteColumns.get( i );
new SqlSelectionImpl( subQuerySelectClause.addSqlSelection(
i + 1, new SqlSelectionImpl(
i, i + 1,
new ColumnReference( i,
idSelectTableReference, new ColumnReference(
cteColumn.getColumnExpression(), idSelectTableReference,
cteColumn.getJdbcMapping(), cteColumn.getColumnExpression(),
factory cteColumn.getJdbcMapping(),
) factory
) )
)
);
}
}
else {
fkModelPart.forEachSelectable(
(selectionIndex, selectableMapping) -> {
subQuerySelectClause.addSqlSelection(
new SqlSelectionImpl(
selectionIndex + 1,
selectionIndex,
new ColumnReference(
idSelectTableReference,
selectableMapping.getSelectionExpression(),
selectableMapping.getJdbcMapping(),
factory
)
)
);
}
); );
} }
final Expression lhs; final Expression lhs;

View File

@ -11,10 +11,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.mutation.internal.DeleteHandler; import org.hibernate.query.sqm.mutation.internal.DeleteHandler;
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter; import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
import org.hibernate.query.sqm.tree.cte.SqmCteTable; import org.hibernate.query.sqm.tree.cte.SqmCteTable;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.expression.SqmParameter;
@ -27,6 +29,8 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.results.graph.basic.BasicResult;
/** /**
* Bulk-id delete handler that uses CTE and VALUES lists. * Bulk-id delete handler that uses CTE and VALUES lists.
@ -53,12 +57,42 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
Map<SqmParameter, List<JdbcParameter>> parameterResolutions, Map<SqmParameter, List<JdbcParameter>> parameterResolutions,
SessionFactoryImplementor factory) { SessionFactoryImplementor factory) {
final TableGroup updatingTableGroup = sqmConverter.getMutatingTableGroup(); final TableGroup updatingTableGroup = sqmConverter.getMutatingTableGroup();
getEntityDescriptor().visitAttributeMappings( final SelectStatement idSelectStatement = (SelectStatement) idSelectCte.getCteDefinition();
sqmConverter.getProcessingStateStack().push(
new SqlAstQueryPartProcessingStateImpl(
idSelectStatement.getQuerySpec(),
sqmConverter.getCurrentProcessingState(),
sqmConverter.getSqlAstCreationState(),
sqmConverter.getCurrentClauseStack()::getCurrent
)
);
getEntityDescriptor().visitSubTypeAttributeMappings(
attribute -> { attribute -> {
if ( attribute instanceof PluralAttributeMapping ) { if ( attribute instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute; final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute;
if ( pluralAttribute.getSeparateCollectionTable() != null ) { if ( pluralAttribute.getSeparateCollectionTable() != null ) {
// Ensure that the FK target columns are available
final boolean useFkTarget = !( pluralAttribute.getKeyDescriptor()
.getTargetPart() instanceof EntityIdentifierMapping );
if ( useFkTarget ) {
final TableGroup mutatingTableGroup = sqmConverter.getMutatingTableGroup();
pluralAttribute.getKeyDescriptor().getTargetPart().applySqlSelections(
mutatingTableGroup.getNavigablePath(),
mutatingTableGroup,
sqmConverter,
(selection, jdbcMapping) -> {
idSelectStatement.getDomainResultDescriptors().add(
new BasicResult<>(
selection.getValuesArrayPosition(),
null,
jdbcMapping.getJavaTypeDescriptor()
)
);
}
);
}
// this collection has a separate collection table, meaning it is one of: // this collection has a separate collection table, meaning it is one of:
// 1) element-collection // 1) element-collection
// 2) many-to-many // 2) many-to-many
@ -68,7 +102,7 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
// collection table // collection table
final String tableExpression = pluralAttribute.getSeparateCollectionTable(); final String tableExpression = pluralAttribute.getSeparateCollectionTable();
final CteTable dmlResultCte = new CteTable( final CteTable dmlResultCte = new CteTable(
getCteTableName( tableExpression ), getCteTableName( pluralAttribute ),
idSelectCte.getCteTable().getCteColumns(), idSelectCte.getCteTable().getCteColumns(),
factory factory
); );
@ -85,7 +119,12 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
); );
final MutationStatement dmlStatement = new DeleteStatement( final MutationStatement dmlStatement = new DeleteStatement(
dmlTableReference, dmlTableReference,
createIdSubQueryPredicate( columnReferences, idSelectCte, factory ), createIdSubQueryPredicate(
columnReferences,
idSelectCte,
useFkTarget ? pluralAttribute.getKeyDescriptor().getTargetPart() : null,
factory
),
columnReferences columnReferences
); );
statement.addCteStatement( new CteStatement( dmlResultCte, dmlStatement ) ); statement.addCteStatement( new CteStatement( dmlResultCte, dmlStatement ) );
@ -93,6 +132,7 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
} }
} }
); );
sqmConverter.getProcessingStateStack().pop();
getEntityDescriptor().visitConstraintOrderedTables( getEntityDescriptor().visitConstraintOrderedTables(
(tableExpression, tableColumnsVisitationSupplier) -> { (tableExpression, tableColumnsVisitationSupplier) -> {
@ -124,4 +164,12 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
} }
); );
} }
protected String getCteTableName(PluralAttributeMapping pluralAttribute) {
final String hibernateEntityName = pluralAttribute.findContainingEntityMapping().getEntityName();
final String jpaEntityName = getSessionFactory().getJpaMetamodel().entity( hibernateEntityName ).getName();
return DML_RESULT_TABLE_NAME_PREFIX + jpaEntityName + "_" + pluralAttribute.getRootPathName().substring(
hibernateEntityName.length() + 1
);
}
} }

View File

@ -19,6 +19,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.transaction.spi.IsolationDelegate; import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.ComparisonOperator; import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter; import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
@ -162,6 +163,15 @@ public final class ExecuteWithIdTableHelper {
Function<SharedSessionContractImplementor,String> sessionUidAccess, Function<SharedSessionContractImplementor,String> sessionUidAccess,
EntityMappingType entityDescriptor, EntityMappingType entityDescriptor,
ExecutionContext executionContext) { ExecutionContext executionContext) {
return createIdTableSelectQuerySpec( idTable, null, sessionUidAccess, entityDescriptor, executionContext );
}
public static QuerySpec createIdTableSelectQuerySpec(
IdTable idTable,
ModelPart fkModelPart,
Function<SharedSessionContractImplementor,String> sessionUidAccess,
EntityMappingType entityDescriptor,
ExecutionContext executionContext) {
final QuerySpec querySpec = new QuerySpec( false ); final QuerySpec querySpec = new QuerySpec( false );
final TableReference idTableReference = new TableReference( final TableReference idTableReference = new TableReference(
@ -182,7 +192,7 @@ public final class ExecuteWithIdTableHelper {
querySpec.getFromClause().addRoot( idTableGroup ); querySpec.getFromClause().addRoot( idTableGroup );
applyIdTableSelections( querySpec, idTableReference, idTable, executionContext ); applyIdTableSelections( querySpec, idTableReference, idTable, fkModelPart, executionContext );
applyIdTableRestrictions( querySpec, idTableReference, idTable, sessionUidAccess, executionContext ); applyIdTableRestrictions( querySpec, idTableReference, idTable, sessionUidAccess, executionContext );
return querySpec; return querySpec;
@ -192,34 +202,59 @@ public final class ExecuteWithIdTableHelper {
QuerySpec querySpec, QuerySpec querySpec,
TableReference tableReference, TableReference tableReference,
IdTable idTable, IdTable idTable,
ModelPart fkModelPart,
ExecutionContext executionContext) { ExecutionContext executionContext) {
for ( int i = 0; i < idTable.getIdTableColumns().size(); i++ ) { if ( fkModelPart == null ) {
final IdTableColumn idTableColumn = idTable.getIdTableColumns().get( i ); final int size = idTable.getEntityDescriptor().getIdentifierMapping().getJdbcTypeCount();
if ( idTableColumn != idTable.getSessionUidColumn() ) { for ( int i = 0; i < size; i++ ) {
querySpec.getSelectClause().addSqlSelection( final IdTableColumn idTableColumn = idTable.getIdTableColumns().get( i );
new SqlSelectionImpl( if ( idTableColumn != idTable.getSessionUidColumn() ) {
i + 1, querySpec.getSelectClause().addSqlSelection(
i, new SqlSelectionImpl(
new ColumnReference( i + 1,
tableReference, i,
idTableColumn.getColumnName(), new ColumnReference(
false, tableReference,
null, idTableColumn.getColumnName(),
null, false,
idTableColumn.getJdbcMapping(), null,
executionContext.getSession().getFactory() null,
) idTableColumn.getJdbcMapping(),
) executionContext.getSession().getFactory()
); )
)
);
}
} }
} }
else {
fkModelPart.forEachSelectable(
(i, selectableMapping) -> {
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
i + 1,
i,
new ColumnReference(
tableReference,
selectableMapping.getSelectionExpression(),
false,
null,
null,
selectableMapping.getJdbcMapping(),
executionContext.getSession().getFactory()
)
)
);
}
);
}
} }
private static void applyIdTableRestrictions( private static void applyIdTableRestrictions(
QuerySpec querySpec, QuerySpec querySpec,
TableReference idTableReference, TableReference idTableReference,
IdTable idTable, IdTable idTable,
Function<SharedSessionContractImplementor,String> sessionUidAccess, Function<SharedSessionContractImplementor, String> sessionUidAccess,
ExecutionContext executionContext) { ExecutionContext executionContext) {
if ( idTable.getSessionUidColumn() != null ) { if ( idTable.getSessionUidColumn() != null ) {
querySpec.applyPredicate( querySpec.applyPredicate(

View File

@ -13,8 +13,12 @@ import java.util.function.Function;
import org.hibernate.boot.model.relational.Exportable; import org.hibernate.boot.model.relational.Exportable;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.mapping.Contributable; import org.hibernate.mapping.Contributable;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
import org.hibernate.sql.ast.tree.from.TableGroup;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -51,6 +55,32 @@ public class IdTable implements Exportable, Contributable {
) )
) )
); );
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 ) ) {
fkTarget.forEachSelectable(
(columnIndex, selection) -> columns.add(
new IdTableColumn(
this,
selection.getSelectionExpression(),
selection.getJdbcMapping(),
dialect.getTypeName(
selection.getJdbcMapping().getJdbcTypeDescriptor()
)
)
)
);
}
}
}
}
);
this.dialect = dialect; this.dialect = dialect;
} }

View File

@ -24,6 +24,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.FilterHelper; import org.hibernate.internal.FilterHelper;
import org.hibernate.internal.util.MutableInteger; import org.hibernate.internal.util.MutableInteger;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
@ -448,7 +449,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
executionContext executionContext
); );
final QuerySpec idTableSubQuery = ExecuteWithIdTableHelper.createIdTableSelectQuerySpec( final QuerySpec idTableIdentifierSubQuery = ExecuteWithIdTableHelper.createIdTableSelectQuerySpec(
idTable, idTable,
sessionUidAccess, sessionUidAccess,
entityDescriptor, entityDescriptor,
@ -459,14 +460,26 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
entityDescriptor, entityDescriptor,
(tableReference, attributeMapping) -> { (tableReference, attributeMapping) -> {
final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor(); final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor();
final QuerySpec idTableFkSubQuery;
if ( fkDescriptor.getTargetPart() instanceof EntityIdentifierMapping ) {
idTableFkSubQuery = idTableIdentifierSubQuery;
}
else {
idTableFkSubQuery = ExecuteWithIdTableHelper.createIdTableSelectQuerySpec(
idTable,
fkDescriptor.getTargetPart(),
sessionUidAccess,
entityDescriptor,
executionContext
);
}
return new InSubQueryPredicate( return new InSubQueryPredicate(
MappingModelHelper.buildColumnReferenceExpression( MappingModelHelper.buildColumnReferenceExpression(
fkDescriptor, fkDescriptor,
null, null,
sessionFactory sessionFactory
), ),
idTableSubQuery, idTableFkSubQuery,
false false
); );
@ -479,7 +492,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
(tableExpression, tableKeyColumnVisitationSupplier) -> deleteFromTableUsingIdTable( (tableExpression, tableKeyColumnVisitationSupplier) -> deleteFromTableUsingIdTable(
tableExpression, tableExpression,
tableKeyColumnVisitationSupplier, tableKeyColumnVisitationSupplier,
idTableSubQuery, idTableIdentifierSubQuery,
executionContext executionContext
) )
); );

View File

@ -13,6 +13,7 @@ import java.util.function.Supplier;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
@ -48,6 +49,8 @@ public class InPredicateRestrictionProducer implements MatchingIdRestrictionProd
public InListPredicate produceRestriction( public InListPredicate produceRestriction(
List<?> matchingIdValues, List<?> matchingIdValues,
EntityMappingType entityDescriptor, EntityMappingType entityDescriptor,
int valueIndex,
ModelPart valueModelPart,
TableReference mutatingTableReference, TableReference mutatingTableReference,
Supplier<Consumer<SelectableConsumer>> columnsToMatchVisitationSupplier, Supplier<Consumer<SelectableConsumer>> columnsToMatchVisitationSupplier,
ExecutionContext executionContext) { ExecutionContext executionContext) {

View File

@ -12,6 +12,10 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.MutableInteger;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
@ -69,13 +73,13 @@ public class InlineDeleteHandler implements DeleteHandler {
@Override @Override
public int execute(DomainQueryExecutionContext executionContext) { public int execute(DomainQueryExecutionContext executionContext) {
final List<Object> ids = MatchingIdSelectionHelper.selectMatchingIds( final List<Object> idsAndFks = MatchingIdSelectionHelper.selectMatchingIds(
sqmDeleteStatement, sqmDeleteStatement,
domainParameterXref, domainParameterXref,
executionContext executionContext
); );
if ( ids == null || ids.isEmpty() ) { if ( idsAndFks == null || idsAndFks.isEmpty() ) {
return 0; return 0;
} }
@ -87,8 +91,8 @@ public class InlineDeleteHandler implements DeleteHandler {
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( domainParameterXref.getQueryParameterCount() ); final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( domainParameterXref.getQueryParameterCount() );
// delete from the tables // delete from the tables
final MutableInteger valueIndexCounter = new MutableInteger();
entityDescriptor.visitAttributeMappings( entityDescriptor.visitSubTypeAttributeMappings(
attribute -> { attribute -> {
if ( attribute instanceof PluralAttributeMapping ) { if ( attribute instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute; final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute;
@ -101,18 +105,29 @@ public class InlineDeleteHandler implements DeleteHandler {
// //
// in all of these cases, we should clean up the matching rows in the // in all of these cases, we should clean up the matching rows in the
// collection table // collection table
final ModelPart fkTargetPart = pluralAttribute.getKeyDescriptor().getTargetPart();
final int valueIndex;
if ( fkTargetPart instanceof EntityIdentifierMapping ) {
valueIndex = 0;
}
else {
if ( valueIndexCounter.get() == 0 ) {
valueIndexCounter.set( entityDescriptor.getIdentifierMapping().getJdbcTypeCount() );
}
valueIndex = valueIndexCounter.get();
valueIndexCounter.plus( fkTargetPart.getJdbcTypeCount() );
}
// todo (6.0) : implement this executeDelete(
// executeDelete( pluralAttribute.getSeparateCollectionTable(),
// pluralAttribute.getSeparateCollectionTable(), entityDescriptor,
// matchingIdsPredicateProducer.produceRestriction( () -> fkTargetPart::forEachSelectable,
// ids, idsAndFks,
// () -> columnConsumer -> , valueIndex,
// executionContext fkTargetPart,
// ), jdbcParameterBindings,
// jdbcParameterBindings, executionContext
// executionContext );
// );
} }
} }
} }
@ -124,14 +139,16 @@ public class InlineDeleteHandler implements DeleteHandler {
tableExpression, tableExpression,
entityDescriptor, entityDescriptor,
tableKeyColumnsVisitationSupplier, tableKeyColumnsVisitationSupplier,
ids, idsAndFks,
0,
null,
jdbcParameterBindings, jdbcParameterBindings,
executionContext executionContext
); );
} }
); );
return ids.size(); return idsAndFks.size();
} }
private void executeDelete( private void executeDelete(
@ -139,6 +156,8 @@ public class InlineDeleteHandler implements DeleteHandler {
EntityMappingType entityDescriptor, EntityMappingType entityDescriptor,
Supplier<Consumer<SelectableConsumer>> tableKeyColumnsVisitationSupplier, Supplier<Consumer<SelectableConsumer>> tableKeyColumnsVisitationSupplier,
List<Object> ids, List<Object> ids,
int valueIndex,
ModelPart valueModelPart,
JdbcParameterBindings jdbcParameterBindings, JdbcParameterBindings jdbcParameterBindings,
DomainQueryExecutionContext executionContext) { DomainQueryExecutionContext executionContext) {
final TableReference targetTableReference = new TableReference( final TableReference targetTableReference = new TableReference(
@ -153,6 +172,8 @@ public class InlineDeleteHandler implements DeleteHandler {
final Predicate matchingIdsPredicate = matchingIdsPredicateProducer.produceRestriction( final Predicate matchingIdsPredicate = matchingIdsPredicateProducer.produceRestriction(
ids, ids,
entityDescriptor, entityDescriptor,
valueIndex,
valueModelPart,
targetTableReference, targetTableReference,
tableKeyColumnsVisitationSupplier, tableKeyColumnsVisitationSupplier,
executionContextAdapter executionContextAdapter

View File

@ -10,6 +10,7 @@ import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
@ -33,6 +34,8 @@ public interface MatchingIdRestrictionProducer {
Predicate produceRestriction( Predicate produceRestriction(
List<?> matchingIdValues, List<?> matchingIdValues,
EntityMappingType entityDescriptor, EntityMappingType entityDescriptor,
int valueIndex,
ModelPart valueModelPart,
TableReference mutatingTableReference, TableReference mutatingTableReference,
Supplier<Consumer<SelectableConsumer>> columnsToMatchVisitationSupplier, Supplier<Consumer<SelectableConsumer>> columnsToMatchVisitationSupplier,
ExecutionContext executionContext); ExecutionContext executionContext);

View File

@ -9,6 +9,8 @@ package org.hibernate.sql.ast.tree.from;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
@ -68,7 +70,15 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat
@Override @Override
default void applySqlSelections(DomainResultCreationState creationState) { default void applySqlSelections(DomainResultCreationState creationState) {
getModelPart().applySqlSelections( final ModelPartContainer modelPart = getModelPart();
final ModelPart modelPartToApply;
if ( modelPart instanceof EntityValuedModelPart ) {
modelPartToApply = ( (EntityValuedModelPart) modelPart ).getEntityMappingType();
}
else {
modelPartToApply = modelPart;
}
modelPartToApply.applySqlSelections(
getNavigablePath(), getNavigablePath(),
creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup( getNavigablePath() ), creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup( getNavigablePath() ),
creationState creationState

View File

@ -700,7 +700,7 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
} }
@Override @Override
public void visitAttributeMappings(Consumer<AttributeMapping> action) { public void visitAttributeMappings(Consumer<? super AttributeMapping> action) {
} }

View File

@ -714,7 +714,7 @@ public class PersisterClassProviderTest {
} }
@Override @Override
public void visitAttributeMappings(Consumer<AttributeMapping> action) { public void visitAttributeMappings(Consumer<? super AttributeMapping> action) {
} }

View File

@ -815,7 +815,7 @@ public class CustomPersister implements EntityPersister {
} }
@Override @Override
public void visitAttributeMappings(Consumer<AttributeMapping> action) { public void visitAttributeMappings(Consumer<? super AttributeMapping> action) {
} }