From 5635a33ab7681bcd5996d334561f18eb4ab706cd Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Fri, 25 Aug 2023 10:53:55 +0200 Subject: [PATCH] HHH-17105 Include custom sql restriction in join table mutations --- .../AbstractCollectionPersister.java | 3 +- .../collection/BasicCollectionPersister.java | 14 ++++++-- .../collection/OneToManyPersister.java | 23 ++++++++++--- .../sqm/internal/SimpleDeleteQueryPlan.java | 33 +++++++++++++++---- .../sql/ast/spi/AbstractSqlAstTranslator.java | 4 +++ .../builder/TableDeleteBuilderStandard.java | 21 ++++++++---- .../builder/TableUpdateBuilderStandard.java | 17 +++++++++- .../model/internal/TableDeleteStandard.java | 18 ++++++++++ .../model/internal/TableUpdateStandard.java | 16 +++++++-- 9 files changed, 126 insertions(+), 23 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 01ad7819a8..aa7e8bb3aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -1782,7 +1782,8 @@ public abstract class AbstractCollectionPersister "one-shot delete for " + getRolePath(), keyRestrictionBindings, Collections.emptyList(), - parameterBinders + parameterBinders, + sqlWhereString ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java index 0b89798be8..115cb1e84d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java @@ -458,7 +458,12 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { final PluralAttributeMapping attribute = getAttributeMapping(); assert attribute != null; - final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( this, tableReference, getFactory() ); + final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( + this, + tableReference, + getFactory(), + sqlWhereString + ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SET @@ -667,7 +672,12 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { final ForeignKeyDescriptor fkDescriptor = pluralAttribute.getKeyDescriptor(); assert fkDescriptor != null; - final TableDeleteBuilderStandard deleteBuilder = new TableDeleteBuilderStandard( this, tableReference, getFactory() ); + final TableDeleteBuilderStandard deleteBuilder = new TableDeleteBuilderStandard( + this, + tableReference, + getFactory(), + sqlWhereString + ); if ( pluralAttribute.getIdentifierDescriptor() != null ) { deleteBuilder.addKeyRestrictionsLeniently( pluralAttribute.getIdentifierDescriptor() ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java index b3268a09d2..a392817787 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java @@ -564,7 +564,12 @@ public class OneToManyPersister extends AbstractCollectionPersister { } public RestrictedTableMutation generateDeleteRowAst(MutatingTableReference tableReference) { - final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( this, tableReference, getFactory() ); + final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( + this, + tableReference, + getFactory(), + sqlWhereString + ); // for each key column - // 1) set the value to null @@ -654,9 +659,14 @@ public class OneToManyPersister extends AbstractCollectionPersister { } private TableUpdate buildTableUpdate(MutatingTableReference tableReference) { - final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( this, tableReference, getFactory() ); - final PluralAttributeMapping attributeMapping = getAttributeMapping(); + final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( + this, + tableReference, + getFactory(), + sqlWhereString + ); + final PluralAttributeMapping attributeMapping = getAttributeMapping(); attributeMapping.getKeyDescriptor().getKeyPart().forEachSelectable( updateBuilder ); final CollectionPart indexDescriptor = attributeMapping.getIndexDescriptor(); @@ -757,7 +767,12 @@ public class OneToManyPersister extends AbstractCollectionPersister { } private JdbcMutationOperation buildGeneratedWriteIndexOperation(MutatingTableReference tableReference) { - final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( this, tableReference, getFactory() ); + final TableUpdateBuilderStandard updateBuilder = new TableUpdateBuilderStandard<>( + this, + tableReference, + getFactory(), + sqlWhereString + ); final OneToManyCollectionPart elementDescriptor = (OneToManyCollectionPart) getAttributeMapping().getElementDescriptor(); updateBuilder.addKeyRestrictionsLeniently( elementDescriptor.getAssociatedEntityMappingType().getIdentifierMapping() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java index 9e39658ac3..c4a254e718 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java @@ -10,9 +10,11 @@ import java.util.List; import java.util.Map; import org.hibernate.action.internal.BulkOperationCleanupAction; +import org.hibernate.dialect.DmlTargetColumnQualifierSupport; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.MutableObject; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.MappingModelExpressible; @@ -35,7 +37,9 @@ import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.from.MutatingTableReferenceGroupWrapper; import org.hibernate.sql.ast.tree.from.NamedTableReference; +import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; +import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.exec.spi.JdbcOperationQueryDelete; import org.hibernate.sql.exec.spi.JdbcParameterBindings; @@ -136,17 +140,29 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan { SqmMutationStrategyHelper.cleanUpCollectionTables( entityDescriptor, (tableReference, attributeMapping) -> { + final TableGroup collectionTableGroup = new MutatingTableReferenceGroupWrapper( + new NavigablePath( attributeMapping.getRootPathName() ), + attributeMapping, + (NamedTableReference) tableReference + ); + + final MutableObject additionalPredicate = new MutableObject<>(); + attributeMapping.applyBaseRestrictions( + p -> additionalPredicate.set( Predicate.combinePredicates( additionalPredicate.get(), p ) ), + collectionTableGroup, + factory.getJdbcServices().getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS, + executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters(), + null, + null + ); + if ( missingRestriction ) { - return null; + return additionalPredicate.get(); } final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor(); final Expression fkColumnExpression = MappingModelCreationHelper.buildColumnReferenceExpression( - new MutatingTableReferenceGroupWrapper( - new NavigablePath( attributeMapping.getRootPathName() ), - attributeMapping, - (NamedTableReference) tableReference - ), + collectionTableGroup, fkDescriptor.getKeyPart(), null, factory @@ -178,7 +194,10 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan { session ) ); - return new InSubQueryPredicate( fkColumnExpression, matchingIdSubQuery, false ); + return Predicate.combinePredicates( + additionalPredicate.get(), + new InSubQueryPredicate( fkColumnExpression, matchingIdSubQuery, false ) + ); }, ( missingRestriction ? JdbcParameterBindings.NO_BINDINGS : jdbcParameterBindings ), executionContextAdapter diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java index 3e34ea1142..15d0a54498 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java @@ -8126,6 +8126,10 @@ public abstract class AbstractSqlAstTranslator implemen } } ); } + + if ( tableDelete.getWhereFragment() != null ) { + sqlBuffer.append( " and (" ).append( tableDelete.getWhereFragment() ).append( ")" ); + } } finally { getCurrentClauseStack().pop(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderStandard.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderStandard.java index 9f93f282b8..10fcbe778f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderStandard.java @@ -6,15 +6,12 @@ */ package org.hibernate.sql.model.ast.builder; -import java.util.ArrayList; -import java.util.List; - import org.hibernate.HibernateException; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.StringHelper; import org.hibernate.sql.model.MutationTarget; import org.hibernate.sql.model.MutationType; import org.hibernate.sql.model.TableMapping; -import org.hibernate.sql.model.ast.ColumnValueParameter; import org.hibernate.sql.model.ast.MutatingTableReference; import org.hibernate.sql.model.ast.TableDelete; import org.hibernate.sql.model.internal.TableDeleteCustomSql; @@ -34,21 +31,32 @@ public class TableDeleteBuilderStandard private String sqlComment; + private final String whereFragment; + public TableDeleteBuilderStandard( MutationTarget mutationTarget, TableMapping table, SessionFactoryImplementor sessionFactory) { - this( mutationTarget, new MutatingTableReference( table ), sessionFactory ); + this( mutationTarget, new MutatingTableReference( table ), sessionFactory, null ); } public TableDeleteBuilderStandard( MutationTarget mutationTarget, MutatingTableReference tableReference, SessionFactoryImplementor sessionFactory) { + this( mutationTarget, tableReference, sessionFactory, null ); + } + + public TableDeleteBuilderStandard( + MutationTarget mutationTarget, + MutatingTableReference tableReference, + SessionFactoryImplementor sessionFactory, + String whereFragment) { super( MutationType.DELETE, mutationTarget, tableReference, sessionFactory ); this.isCustomSql = tableReference.getTableMapping().getDeleteDetails().getCustomSql() != null; this.sqlComment = "delete for " + mutationTarget.getRolePath(); + this.whereFragment = whereFragment; } public String getSqlComment() { @@ -98,7 +106,8 @@ public class TableDeleteBuilderStandard sqlComment, getKeyRestrictionBindings(), getOptimisticLockBindings(), - getParameters() + getParameters(), + whereFragment ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderStandard.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderStandard.java index d259e07bd2..fb481ee574 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderStandard.java @@ -8,7 +8,9 @@ package org.hibernate.sql.model.ast.builder; import java.util.List; +import org.hibernate.HibernateException; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.StringHelper; import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationTarget; import org.hibernate.sql.model.TableMapping; @@ -26,19 +28,30 @@ import org.hibernate.sql.model.internal.TableUpdateStandard; * @author Steve Ebersole */ public class TableUpdateBuilderStandard extends AbstractTableUpdateBuilder { + private final String whereFragment; public TableUpdateBuilderStandard( MutationTarget mutationTarget, TableMapping tableMapping, SessionFactoryImplementor sessionFactory) { super( mutationTarget, tableMapping, sessionFactory ); + this.whereFragment = null; } public TableUpdateBuilderStandard( MutationTarget mutationTarget, MutatingTableReference tableReference, SessionFactoryImplementor sessionFactory) { + this( mutationTarget, tableReference, sessionFactory, null ); + } + + public TableUpdateBuilderStandard( + MutationTarget mutationTarget, + MutatingTableReference tableReference, + SessionFactoryImplementor sessionFactory, + String whereFragment) { super( mutationTarget, tableReference, sessionFactory ); + this.whereFragment = whereFragment; } @SuppressWarnings("unchecked") @@ -76,7 +89,9 @@ public class TableUpdateBuilderStandard extends Abs getSqlComment(), valueBindings, getKeyRestrictionBindings(), - getOptimisticLockBindings() + getOptimisticLockBindings(), + whereFragment, + null ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableDeleteStandard.java b/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableDeleteStandard.java index ab19d38120..04a70a94b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableDeleteStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableDeleteStandard.java @@ -19,6 +19,8 @@ import org.hibernate.sql.model.ast.MutatingTableReference; * @author Steve Ebersole */ public class TableDeleteStandard extends AbstractTableDelete { + private final String whereFragment; + public TableDeleteStandard( MutatingTableReference mutatingTable, MutationTarget mutationTarget, @@ -26,7 +28,23 @@ public class TableDeleteStandard extends AbstractTableDelete { List keyRestrictionBindings, List optLockRestrictionBindings, List parameters) { + this( mutatingTable, mutationTarget, sqlComment, keyRestrictionBindings, optLockRestrictionBindings, parameters, null ); + } + + public TableDeleteStandard( + MutatingTableReference mutatingTable, + MutationTarget mutationTarget, + String sqlComment, + List keyRestrictionBindings, + List optLockRestrictionBindings, + List parameters, + String whereFragment) { super( mutatingTable, mutationTarget, sqlComment, keyRestrictionBindings, optLockRestrictionBindings, parameters ); + this.whereFragment = whereFragment; + } + + public String getWhereFragment() { + return whereFragment; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableUpdateStandard.java b/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableUpdateStandard.java index 1e7063dc8c..c0d7aa436f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableUpdateStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/internal/TableUpdateStandard.java @@ -32,9 +32,21 @@ public class TableUpdateStandard extends AbstractTableUpdate valueBindings, List keyRestrictionBindings, List optLockRestrictionBindings) { + this( mutatingTable, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings, null, null ); + } + + public TableUpdateStandard( + MutatingTableReference mutatingTable, + MutationTarget mutationTarget, + String sqlComment, + List valueBindings, + List keyRestrictionBindings, + List optLockRestrictionBindings, + String whereFragment, + Expectation expectation) { super( mutatingTable, mutationTarget, sqlComment, valueBindings, keyRestrictionBindings, optLockRestrictionBindings ); - this.whereFragment = null; - this.expectation = null; + this.whereFragment = whereFragment; + this.expectation = expectation; } public TableUpdateStandard(