diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c97654dc0..468fc53ff2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,9 @@ None yet
### Bug fixes
-None yet
+* Fix missing cascading deletes for deletes that contain joins or CTEs
+* Fix some issues with PostgreSQL and Oracle multiset SQL rendering with Hibernate ORM 6+
+* Fix returning clause rendering for PostgreSQL with Hibernate ORM 6+
### Backwards-incompatible changes
diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java b/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java
index 42bf21cfd5..de2842bff7 100644
--- a/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java
+++ b/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java
@@ -950,7 +950,7 @@ private void renderEquality(Expression left, Expression right, boolean negated,
rewriteToIdParam(right);
}
} else {
- if (expressionToSplit == null || dbmsDialect.supportsAnsiRowValueConstructor() || !(left instanceof ParameterExpression) && !(right instanceof ParameterExpression)) {
+ if (expressionToSplit == null || !(left instanceof ParameterExpression) && !(right instanceof ParameterExpression)) {
left.accept(this);
sb.append(operator);
if (quantifier != PredicateQuantifier.ONE) {
diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java
index c2e44130a2..40c1fe5fb0 100644
--- a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java
+++ b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java
@@ -38,8 +38,7 @@ public void render(FunctionRenderContext context, String[] fields, String[] sele
context.addChunk(postChunk);
context.addChunk(subquery.substring(fromIndex));
} else {
- int limitIndex = SqlUtils.indexOfLimit(subquery, orderByIndex);
- if (limitIndex == -1) {
+ if (SqlUtils.indexOfLimit(subquery, orderByIndex) == -1 && SqlUtils.indexOfFetchFirst(subquery, orderByIndex) == -1) {
context.addChunk(preChunk);
StringBuilder sb = new StringBuilder(fromIndex);
diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java
index 8a0fefca71..dde6fc1696 100644
--- a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java
+++ b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java
@@ -26,8 +26,7 @@ public void render(FunctionRenderContext context, String[] fields, String[] sele
context.addChunk("))");
context.addChunk(subquery.substring(fromIndex));
} else {
- int limitIndex = SqlUtils.indexOfLimit(subquery, orderByIndex);
- if (limitIndex == -1) {
+ if (SqlUtils.indexOfLimit(subquery, orderByIndex) == -1 && SqlUtils.indexOfFetchFirst(subquery, orderByIndex) == -1) {
renderJsonObjectArguments(context, fields, selectItemExpressions);
context.addChunk("))");
context.addChunk(" OVER (");
diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java
index d88768c7c5..df7851f706 100644
--- a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java
+++ b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java
@@ -26,8 +26,7 @@ public void render(FunctionRenderContext context, String[] fields, String[] sele
context.addChunk("))");
context.addChunk(subquery.substring(fromIndex));
} else {
- int limitIndex = SqlUtils.indexOfLimit(subquery, orderByIndex);
- if (limitIndex == -1) {
+ if (SqlUtils.indexOfLimit(subquery, orderByIndex) == -1 && SqlUtils.indexOfFetchFirst(subquery, orderByIndex) == -1) {
renderXmlElementArguments(context, fields, selectItemExpressions);
context.addChunk("))");
context.addChunk(" OVER (");
diff --git a/core/testsuite-hibernate/pom.xml b/core/testsuite-hibernate/pom.xml
index 9197e9d580..69687dfbbe 100644
--- a/core/testsuite-hibernate/pom.xml
+++ b/core/testsuite-hibernate/pom.xml
@@ -13,7 +13,7 @@
com.blazebit.persistence.core.testsuite.hibernate
- com.blazebit.persistence.testsuite
+ com.blazebit.persistence.testsuite.hibernate
0
@@ -634,5 +634,20 @@
+
+
+ eclipselink
+
+
+
+ maven-compiler-plugin
+
+ true
+ true
+
+
+
+
+
diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/IntegerProperty.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/IntegerProperty.java
similarity index 93%
rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/IntegerProperty.java
rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/IntegerProperty.java
index fb1590cbb2..80b894d573 100644
--- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/IntegerProperty.java
+++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/IntegerProperty.java
@@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
* Copyright Blazebit
*/
-package com.blazebit.persistence.testsuite.hibernate6.entity;
+package com.blazebit.persistence.testsuite.hibernate.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/Property.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/Property.java
similarity index 69%
rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/Property.java
rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/Property.java
index 0642001176..f09bf115ff 100644
--- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/Property.java
+++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/Property.java
@@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
* Copyright Blazebit
*/
-package com.blazebit.persistence.testsuite.hibernate6.entity;
+package com.blazebit.persistence.testsuite.hibernate.entity;
public interface Property {
diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/PropertyHolder.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/PropertyHolder.java
similarity index 95%
rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/PropertyHolder.java
rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/PropertyHolder.java
index ce28991a94..2a0fa10966 100644
--- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/PropertyHolder.java
+++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/PropertyHolder.java
@@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
* Copyright Blazebit
*/
-package com.blazebit.persistence.testsuite.hibernate6.entity;
+package com.blazebit.persistence.testsuite.hibernate.entity;
import jakarta.persistence.Column;
import jakarta.persistence.DiscriminatorType;
diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/StringProperty.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/StringProperty.java
similarity index 93%
rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/StringProperty.java
rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/StringProperty.java
index 232b1b7fbc..fc98840bd5 100644
--- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/StringProperty.java
+++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/StringProperty.java
@@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
* Copyright Blazebit
*/
-package com.blazebit.persistence.testsuite.hibernate6.entity;
+package com.blazebit.persistence.testsuite.hibernate.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
diff --git a/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java b/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java
index 46726c751d..f9a6e80c1e 100644
--- a/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java
+++ b/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java
@@ -6,7 +6,7 @@
import com.blazebit.persistence.CriteriaBuilder;
import com.blazebit.persistence.testsuite.AbstractCoreTest;
-import com.blazebit.persistence.testsuite.hibernate6.entity.PropertyHolder;
+import com.blazebit.persistence.testsuite.hibernate.entity.PropertyHolder;
import org.junit.jupiter.api.Test;
import static org.junit.Assert.assertTrue;
diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java
index f5b2a4a3a0..8160a3e061 100644
--- a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java
+++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java
@@ -205,6 +205,9 @@ protected AssertStatementBuilder deleteDocumentOwned(AssertStatementBuilder buil
.assertDelete().forRelation(Document.class, "peopleListBag").and()
.assertDelete().forRelation(Document.class, "peopleCollectionBag").and();
}
+ if (isQueryStrategy() && !simpleDelete && dbmsDialect.supportsModificationQueryInWithClause()) {
+ return builder;
+ }
if (supportsNestedEmbeddables()) {
builder
.assertDelete().forRelation(Document.class, "nameContainerMap").and()
@@ -228,7 +231,9 @@ protected AssertStatementBuilder deletePersonOwned(AssertStatementBuilder builde
.assertDelete().forRelation(Person.class, "favoriteDocuments").and()
;
}
-
+ if (isQueryStrategy() && !simpleDelete && dbmsDialect.supportsModificationQueryInWithClause()) {
+ return builder;
+ }
return builder
.assertDelete().forRelation(Person.class, "localized").and()
;
diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java
index 7f72397d45..e9e67a94f3 100644
--- a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java
+++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java
@@ -13,6 +13,7 @@
import com.blazebit.persistence.testsuite.base.jpa.assertion.AssertStatementBuilder;
import com.blazebit.persistence.testsuite.base.jpa.category.NoEclipselink;
+import com.blazebit.persistence.testsuite.base.jpa.category.NoHibernate;
import com.blazebit.persistence.testsuite.entity.Document;
import com.blazebit.persistence.testsuite.entity.DocumentForSimpleOneToOne;
import com.blazebit.persistence.testsuite.entity.DocumentInfoSimple;
@@ -32,7 +33,7 @@
*/
@RunWith(Parameterized.class)
// NOTE: Hibernate has a bug when selecting inverse one-to-ones: https://hibernate.atlassian.net/browse/HHH-12885
-@Category({ NoEclipselink.class})
+@Category({ NoHibernate.class, NoEclipselink.class})
public class EntityViewUpdateSubviewInverseOneToOneEntityTest extends AbstractEntityViewUpdateTest {
private DocumentForSimpleOneToOne doc1;
diff --git a/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java b/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java
index 31a9e8d1e9..3d0ef26ffb 100644
--- a/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java
+++ b/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java
@@ -21,17 +21,23 @@
import org.hibernate.HibernateException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ScrollMode;
+import org.hibernate.action.internal.BulkOperationCleanupAction;
+import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
-import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.internal.FilterJdbcParameter;
+import org.hibernate.internal.util.MutableObject;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
import org.hibernate.metamodel.mapping.EntityMappingType;
+import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
+import org.hibernate.metamodel.mapping.PluralAttributeMapping;
+import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
+import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.TupleTransformer;
@@ -58,6 +64,7 @@
import org.hibernate.query.sqm.sql.SqmTranslation;
import org.hibernate.query.sqm.sql.SqmTranslator;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
+import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
@@ -81,12 +88,16 @@
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
+import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.CollectionTableGroup;
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
+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.from.TableReference;
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
import org.hibernate.sql.ast.tree.insert.InsertStatement;
+import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
@@ -108,6 +119,7 @@
import org.hibernate.sql.results.internal.RowTransformerSingularReturnImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
+import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
import org.hibernate.sql.results.spi.ListResultsConsumer;
@@ -131,6 +143,7 @@
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Stream;
@@ -228,43 +241,205 @@ public boolean getSqlContainsLimit() {
@Override
public List getCascadingDeleteSql(EntityManager em, Query query) {
- SessionFactoryImplementor sfi = em.unwrap(SessionImplementor.class).getSessionFactory();
QuerySqmImpl> hqlQuery = query.unwrap(QuerySqmImpl.class);
if (hqlQuery.getSqmStatement() instanceof SqmDeleteStatement>) {
- SqmDeleteStatement> deleteStatement = (SqmDeleteStatement>) hqlQuery.getSqmStatement();
- String mutatingEntityName = deleteStatement.getTarget().getModel().getHibernateEntityName();
- EntityMappingType entityDescriptor = sfi.getMappingMetamodel().getEntityDescriptor(mutatingEntityName);
- SqlAstTranslatorFactory sqlAstTranslatorFactory = sfi.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
- List deleteSqls = new ArrayList<>();
- entityDescriptor.visitConstraintOrderedTables(
- (tableExpression, tableKeyColumnsVisitationSupplier) -> {
-
- // final TableReference targetTableReference = new TableReference(
- // tableExpression,
- // null,
- // false,
- // sfi
- // );
-
- final Predicate matchingIdsPredicate = null;//new InSubQueryPredicate();
- // matchingIdsPredicateProducer.produceRestriction(
- // ids,
- // entityDescriptor,
- // targetTableReference,
- // tableKeyColumnsVisitationSupplier,
- // query
- // );
-
- // final SqlAstDeleteTranslator sqlAstTranslator = sqlAstTranslatorFactory.buildDeleteTranslator( sfi );
- // final JdbcDelete jdbcOperation = sqlAstTranslator.translate( new DeleteStatement( targetTableReference, matchingIdsPredicate ) );
- }
- );
+ List deletes = getCollectionTableDeletes( hqlQuery ).deletes;
+
+ List deleteSqls = new ArrayList<>( deletes.size() );
+ for ( JdbcOperationQueryMutation delete : deletes ) {
+ deleteSqls.add( delete.getSqlString() );
+ }
return deleteSqls;
}
return Collections.EMPTY_LIST;
}
+ private static class CollectionTableDeleteInfo {
+ private final List deletes;
+ private final JdbcParameterBindings parameterBindings;
+
+ public CollectionTableDeleteInfo(
+ List deletes,
+ JdbcParameterBindings parameterBindings) {
+ this.deletes = deletes;
+ this.parameterBindings = parameterBindings;
+ }
+ }
+
+ private static CollectionTableDeleteInfo getCollectionTableDeletes(QuerySqmImpl> hqlQuery) {
+ SessionFactoryImplementor sfi = hqlQuery.getSessionFactory();
+ SqmDeleteStatement> deleteStatement = (SqmDeleteStatement>) hqlQuery.getSqmStatement();
+ String mutatingEntityName = deleteStatement.getTarget().getModel().getHibernateEntityName();
+ EntityMappingType entityDescriptor = sfi.getMappingMetamodel().getEntityDescriptor(mutatingEntityName);
+
+ CacheableSqmInterpretation sqmInterpretation = buildQueryPlan( hqlQuery );
+
+ Map, Map, List>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
+ hqlQuery.getDomainParameterXref(),
+ sqmInterpretation.getSqmTranslation()::getJdbcParamsBySqmParam
+ );
+
+ final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
+ hqlQuery.getQueryParameterBindings(),
+ hqlQuery.getDomainParameterXref(),
+ jdbcParamsXref,
+ sfi.getRuntimeMetamodels().getMappingMetamodel(),
+ sqmInterpretation.getSqmTranslation().getFromClauseAccess()::findTableGroup,
+ new SqmParameterMappingModelResolutionAccess() {
+ @Override @SuppressWarnings("unchecked")
+ public MappingModelExpressible getResolvedMappingModelType(SqmParameter parameter) {
+ return (MappingModelExpressible) sqmInterpretation.getSqmTranslation().getSqmParameterMappingModelTypeResolutions().get(parameter);
+ }
+ },
+ hqlQuery.getSession()
+ );
+ DeleteStatement sqlAst = (DeleteStatement) sqmInterpretation.getSqmTranslation().getSqlAst();
+ final boolean missingRestriction = sqlAst.getRestriction() == null;
+ return new CollectionTableDeleteInfo( getCollectionTableDeletes(
+ 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,
+ sfi.getJdbcServices().getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS,
+ hqlQuery.getSession().getLoadQueryInfluencers().getEnabledFilters(),
+ false,
+ null,
+ null
+ );
+
+ if ( missingRestriction ) {
+ return additionalPredicate.get();
+ }
+
+ final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor();
+ final Expression fkColumnExpression = MappingModelCreationHelper.buildColumnReferenceExpression(
+ collectionTableGroup,
+ fkDescriptor.getKeyPart(),
+ null,
+ sfi
+ );
+
+ final QuerySpec matchingIdSubQuery = new QuerySpec( false );
+
+ final MutatingTableReferenceGroupWrapper tableGroup = new MutatingTableReferenceGroupWrapper(
+ new NavigablePath( attributeMapping.getRootPathName() ),
+ attributeMapping,
+ sqlAst.getTargetTable()
+ );
+ final Expression fkTargetColumnExpression = MappingModelCreationHelper.buildColumnReferenceExpression(
+ tableGroup,
+ fkDescriptor.getTargetPart(),
+ sqmInterpretation.getSqmTranslation().getSqlExpressionResolver(),
+ sfi
+ );
+ matchingIdSubQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, fkTargetColumnExpression ) );
+
+ matchingIdSubQuery.getFromClause().addRoot(
+ tableGroup
+ );
+
+ matchingIdSubQuery.applyPredicate( sqlAst.getRestriction() );
+
+ return Predicate.combinePredicates(
+ additionalPredicate.get(),
+ new InSubQueryPredicate( fkColumnExpression, matchingIdSubQuery, false )
+ );
+ },
+ jdbcParameterBindings,
+ SqmJdbcExecutionContextAdapter.usingLockingAndPaging( hqlQuery )
+ ), jdbcParameterBindings);
+ }
+
+ private static List getCollectionTableDeletes(
+ EntityMappingType entityDescriptor,
+ BiFunction restrictionProducer,
+ JdbcParameterBindings jdbcParameterBindings,
+ ExecutionContext executionContext) {
+ List pluralAttributeMappings = collectCollectionTables( entityDescriptor );
+ List deletes = new ArrayList<>( pluralAttributeMappings.size() );
+ for ( PluralAttributeMapping attributeMapping : pluralAttributeMappings ) {
+ final String separateCollectionTable = attributeMapping.getSeparateCollectionTable();
+
+ final SessionFactoryImplementor sessionFactory = executionContext.getSession().getFactory();
+ final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
+
+ final NamedTableReference tableReference = new NamedTableReference(
+ separateCollectionTable,
+ DeleteStatement.DEFAULT_ALIAS,
+ true
+ );
+
+ final DeleteStatement sqlAstDelete = new DeleteStatement(
+ tableReference,
+ restrictionProducer.apply( tableReference, attributeMapping )
+ );
+
+ deletes.add( jdbcServices.getJdbcEnvironment()
+ .getSqlAstTranslatorFactory()
+ .buildMutationTranslator( sessionFactory, sqlAstDelete )
+ .translate( jdbcParameterBindings, executionContext.getQueryOptions() )
+ );
+ }
+ return deletes;
+ }
+
+ private static List collectCollectionTables(EntityMappingType entityDescriptor) {
+ List pluralAttributeMappings = new ArrayList<>();
+ collectCollectionTables( entityDescriptor, pluralAttributeMappings );
+ return pluralAttributeMappings;
+ }
+
+ private static void collectCollectionTables(EntityMappingType entityDescriptor, List pluralAttributeMappings) {
+ if ( ! entityDescriptor.getEntityPersister().hasCollections() ) {
+ // none to clean-up
+ return;
+ }
+
+ entityDescriptor.visitSubTypeAttributeMappings(
+ attributeMapping -> {
+ if ( attributeMapping instanceof PluralAttributeMapping ) {
+ PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
+ if (pluralAttributeMapping.getSeparateCollectionTable() != null) {
+ pluralAttributeMappings.add( pluralAttributeMapping );
+ }
+ } else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
+ collectCollectionTables(
+ (EmbeddedAttributeMapping) attributeMapping,
+ pluralAttributeMappings
+ );
+ }
+ }
+ );
+ }
+
+ private static void collectCollectionTables(EmbeddedAttributeMapping attributeMapping, List pluralAttributeMappings) {
+ attributeMapping.visitSubParts(
+ modelPart -> {
+ if ( modelPart instanceof PluralAttributeMapping ) {
+ PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
+ if (pluralAttributeMapping.getSeparateCollectionTable() != null) {
+ pluralAttributeMappings.add( pluralAttributeMapping );
+ }
+ } else if ( modelPart instanceof EmbeddedAttributeMapping ) {
+ collectCollectionTables(
+ (EmbeddedAttributeMapping) modelPart,
+ pluralAttributeMappings
+ );
+ }
+ },
+ null
+ );
+ }
+
@Override
public String getSqlAlias(EntityManager em, Query query, String alias, int queryPartNumber) {
QuerySqmImpl> hqlQuery = query.unwrap(QuerySqmImpl.class);
@@ -1017,12 +1192,6 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter queryStrings = new ArrayList<>(participatingQueries.size());
- // Set querySpaces = new HashSet<>();
- // QueryParamEntry queryParametersEntry = createQueryParameters(em, participatingQueries, queryStrings, querySpaces);
- // QueryParameters queryParameters = queryParametersEntry.queryParameters;
-
// Create plan for example query
JdbcOperationQuerySelect exampleQueryJdbcOperation = (JdbcOperationQuerySelect) getJdbcOperation(exampleQuery);
@@ -1036,37 +1205,12 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter returningResult = new HibernateReturningResult