HHH-16392 Fix where clause in collection cleanup subqueries
This commit is contained in:
parent
c16cedf327
commit
a9080f5f7d
|
@ -1427,9 +1427,9 @@ See the <<chapters/domain/basic_types.adoc#mapping-database-generated-value-exam
|
|||
[[annotations-hibernate-where]]
|
||||
==== `@SQLRestriction`
|
||||
|
||||
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/SQLRestriction.html[`@SQLRestriction`] annotation is used to specify a custom SQL `WHERE` clause used when fetching an entity or a collection.
|
||||
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/SQLRestriction.html[`@SQLRestriction`] annotation is used to specify a custom SQL `WHERE` clause used to filter out entities or collections.
|
||||
|
||||
See the <<chapters/pc/PersistenceContext.adoc#pc-where-example,`@SQLRestriction` mapping>> section for more info.
|
||||
See the <<chapters/pc/PersistenceContext.adoc#pc-where,`@SQLRestriction` mapping>> section for more info.
|
||||
|
||||
[[annotations-hibernate-wherejointable]]
|
||||
==== `@SQLJoinTableRestriction`
|
||||
|
|
|
@ -16,7 +16,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
|
||||
/**
|
||||
* Specifies a restriction written in native SQL to add to the generated
|
||||
* SQL when querying an entity or collection.
|
||||
* SQL for entities or collections.
|
||||
* <p>
|
||||
* For example, {@code @SQLRestriction} could be used to hide entity
|
||||
* instances which have been soft-deleted, either for the entity class
|
||||
|
|
|
@ -16,7 +16,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
|
||||
/**
|
||||
* Specifies a restriction written in native SQL to add to the generated
|
||||
* SQL when querying an entity or collection.
|
||||
* SQL for entities or collections.
|
||||
* <p>
|
||||
* For example, {@code @Where} could be used to hide entity instances which
|
||||
* have been soft-deleted, either for the entity class itself:
|
||||
|
|
|
@ -124,8 +124,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
jdbcDelete = deleteTranslator.translate( jdbcParameterBindings, executionContext.getQueryOptions() );
|
||||
}
|
||||
|
||||
final boolean missingRestriction = sqmDelete.getWhereClause() == null
|
||||
|| sqmDelete.getWhereClause().getPredicate() == null;
|
||||
final boolean missingRestriction = sqmInterpretation.getSqlAst().getRestriction() == null;
|
||||
if ( missingRestriction ) {
|
||||
assert domainParameterXref.getSqmParameterCount() == 0;
|
||||
assert jdbcParamsXref.isEmpty();
|
||||
|
@ -171,7 +170,12 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
tableGroup
|
||||
);
|
||||
|
||||
matchingIdSubQuery.applyPredicate( sqmInterpretation.getSqlAst().getRestriction() );
|
||||
matchingIdSubQuery.applyPredicate( SqmMutationStrategyHelper.getIdSubqueryPredicate(
|
||||
sqmInterpretation.getSqlAst().getRestriction(),
|
||||
entityDescriptor,
|
||||
tableGroup,
|
||||
session
|
||||
) );
|
||||
|
||||
return new InSubQueryPredicate( fkColumnExpression, matchingIdSubQuery, false );
|
||||
},
|
||||
|
|
|
@ -6,17 +6,24 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||
import org.hibernate.persister.internal.SqlFragmentPredicate;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
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.predicate.FilterPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
@ -179,4 +186,86 @@ public class SqmMutationStrategyHelper {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the original delete predicate to be used in the id subquery
|
||||
* forcing the use of the table alias qualifier
|
||||
*/
|
||||
public static Predicate getIdSubqueryPredicate(
|
||||
Predicate predicate,
|
||||
EntityMappingType entityDescriptor,
|
||||
TableGroup tableGroup,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( predicate instanceof FilterPredicate || predicate instanceof SqlFragmentPredicate ) {
|
||||
return getBaseRestrictions( entityDescriptor, tableGroup, session ).get( 0 );
|
||||
}
|
||||
else if ( predicate instanceof Junction ) {
|
||||
final Junction original = (Junction) predicate;
|
||||
if ( original.getPredicates().size() > 1 ) {
|
||||
final Junction junction = new Junction(
|
||||
original.getNature(),
|
||||
original.getExpressionType()
|
||||
);
|
||||
junction.getPredicates().addAll( original.getPredicates() );
|
||||
final Predicate secondToLastPredicate = junction.getPredicates().get( junction.getPredicates().size() - 2 );
|
||||
final Predicate lastPredicate = junction.getPredicates().get( junction.getPredicates().size() - 1 );
|
||||
int filterPredicateIndex = -1;
|
||||
int fragmentPredicateIndex = -1;
|
||||
if ( lastPredicate instanceof Junction ) {
|
||||
// If the mutation query specified an explicit where condition and there are multiple base
|
||||
// restrictions they will be in a nested Junction predicate, so we need to process that one
|
||||
final Predicate baseRestrictions = getIdSubqueryPredicate(
|
||||
lastPredicate,
|
||||
entityDescriptor,
|
||||
tableGroup,
|
||||
session
|
||||
);
|
||||
junction.getPredicates().set( junction.getPredicates().size() - 1, baseRestrictions );
|
||||
predicate = junction;
|
||||
}
|
||||
else if ( secondToLastPredicate instanceof FilterPredicate ) {
|
||||
filterPredicateIndex = junction.getPredicates().size() - 2;
|
||||
fragmentPredicateIndex = filterPredicateIndex + 1;
|
||||
}
|
||||
else if ( lastPredicate instanceof FilterPredicate ) {
|
||||
filterPredicateIndex = junction.getPredicates().size() - 1;
|
||||
}
|
||||
else if ( lastPredicate instanceof SqlFragmentPredicate ) {
|
||||
fragmentPredicateIndex = junction.getPredicates().size() - 1;
|
||||
}
|
||||
if ( filterPredicateIndex != -1 || fragmentPredicateIndex != -1 ) {
|
||||
final List<Predicate> baseRestrictions = getBaseRestrictions(
|
||||
entityDescriptor,
|
||||
tableGroup,
|
||||
session
|
||||
);
|
||||
int index = 0;
|
||||
if ( filterPredicateIndex != -1 ) {
|
||||
junction.getPredicates().set( filterPredicateIndex, baseRestrictions.get( index++ ) );
|
||||
}
|
||||
if ( fragmentPredicateIndex != -1 ) {
|
||||
junction.getPredicates().set( fragmentPredicateIndex, baseRestrictions.get( index ) );
|
||||
}
|
||||
predicate = junction;
|
||||
}
|
||||
}
|
||||
}
|
||||
return predicate;
|
||||
}
|
||||
|
||||
private static List<Predicate> getBaseRestrictions(
|
||||
EntityMappingType entityDescriptor,
|
||||
TableGroup tableGroup,
|
||||
SharedSessionContractImplementor session) {
|
||||
final List<Predicate> baseRestrictions = new ArrayList<>( 2 );
|
||||
entityDescriptor.applyBaseRestrictions(
|
||||
baseRestrictions::add,
|
||||
tableGroup,
|
||||
true,
|
||||
session.getLoadQueryInfluencers().getEnabledFilters(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
return baseRestrictions;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue