HHH-14977 - @Where is broken in 6.0

`@Where` and `@Filter` fragments are now fully handled as AST - each fragment gets its own Predicate instance.

Some more work coming to clean up methods we no longer use which require the old String-manip approach.
This commit is contained in:
Steve Ebersole 2021-12-15 17:52:26 -06:00
parent 4e4f2e40b4
commit 1c5ec0612c
19 changed files with 643 additions and 338 deletions

View File

@ -7,25 +7,24 @@
package org.hibernate.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.Filter;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.sql.Template;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.type.Type;
import static org.hibernate.internal.util.StringHelper.safeInterning;
@ -39,12 +38,13 @@ import static org.hibernate.internal.util.StringHelper.safeInterning;
*/
public class FilterHelper {
private static final Pattern FILTER_PARAMETER_PATTERN = Pattern.compile( ":(\\S+)\\.(\\w+)" );
private static final Pattern FILTER_PARAMETER_PATTERN = Pattern.compile( ":(\\S+)(\\w+)" );
private final String[] filterNames;
private final String[] filterConditions;
private final boolean[] filterAutoAliasFlags;
private final Map<String, String>[] filterAliasTableMaps;
private final List<String>[] parameterNames;
/**
* The map of defined filters. This is expected to be in format
@ -56,10 +56,13 @@ public class FilterHelper {
*/
public FilterHelper(List<FilterConfiguration> filters, SessionFactoryImplementor factory) {
int filterCount = filters.size();
filterNames = new String[filterCount];
filterConditions = new String[filterCount];
filterAutoAliasFlags = new boolean[filterCount];
filterAliasTableMaps = new Map[filterCount];
parameterNames = new List[filterCount];
filterCount = 0;
for ( final FilterConfiguration filter : filters ) {
filterAutoAliasFlags[filterCount] = false;
@ -80,13 +83,17 @@ public class FilterHelper {
filterAutoAliasFlags[filterCount] = true;
}
filterConditions[filterCount] = safeInterning(
StringHelper.replace(
filterConditions[filterCount],
":",
":" + filterNames[filterCount] + "."
)
);
final Matcher matcher = FILTER_PARAMETER_PATTERN.matcher( filterConditions[filterCount] );
String copy = filterConditions[filterCount];
final List<String> filterParamNames = new ArrayList<>();
parameterNames[filterCount] = filterParamNames;
while( matcher.find() ) {
final String parameterLabel = filterConditions[filterCount].substring( matcher.start() + 1, matcher.end() );
filterParamNames.add( parameterLabel );
copy = copy.replaceAll( ":" + parameterLabel, ":" + filterNames[filterCount] + "." + parameterLabel );
}
filterConditions[filterCount] = safeInterning( copy );
filterCount++;
}
}
@ -154,113 +161,85 @@ public class FilterHelper {
}
}
public static FilterPredicate createFilterPredicate(
LoadQueryInfluencers loadQueryInfluencers,
Joinable joinable,
TableGroup rootTableGroup) {
return createFilterPredicate( loadQueryInfluencers, joinable, rootTableGroup, true );
}
public static FilterPredicate createFilterPredicate(
Map<String,Filter> enabledFilters,
Joinable joinable,
TableGroup rootTableGroup) {
return createFilterPredicate( enabledFilters, joinable, rootTableGroup, true );
}
public static FilterPredicate createFilterPredicate(
Map<String,Filter> enabledFilters,
Joinable joinable,
TableGroup rootTableGroup,
boolean useIdentificationVariable) {
final String filterFragment = joinable.filterFragment(
rootTableGroup,
enabledFilters,
Collections.emptySet(),
useIdentificationVariable
);
if ( StringHelper.isNotEmpty( filterFragment ) ) {
return doCreateFilterPredicate( filterFragment, enabledFilters );
}
else {
return null;
}
}
public static FilterPredicate createFilterPredicate(
LoadQueryInfluencers loadQueryInfluencers,
Joinable joinable,
TableGroup rootTableGroup,
boolean useIdentificationVariable) {
final String filterFragment = joinable.filterFragment(
rootTableGroup,
loadQueryInfluencers.getEnabledFilters(),
Collections.emptySet(),
useIdentificationVariable
);
if ( StringHelper.isNotEmpty( filterFragment ) ) {
return doCreateFilterPredicate( filterFragment, loadQueryInfluencers.getEnabledFilters() );
}
else {
return null;
public void applyFilters(
FilterAliasGenerator aliasGenerator,
Map<String, Filter> enabledFilters,
Consumer<Predicate> predicateConsumer) {
final FilterPredicate predicate = generateFilterPredicate( aliasGenerator, enabledFilters );
if ( predicate != null ) {
predicateConsumer.accept( predicate );
}
}
public static FilterPredicate createManyToManyFilterPredicate(LoadQueryInfluencers loadQueryInfluencers, CollectionPersister collectionPersister, TableGroup tableGroup) {
assert collectionPersister.isManyToMany();
final String filterFragment = collectionPersister.getManyToManyFilterFragment( tableGroup, loadQueryInfluencers.getEnabledFilters() );
if ( StringHelper.isNotEmpty( filterFragment ) ) {
return doCreateFilterPredicate( filterFragment, loadQueryInfluencers.getEnabledFilters() );
}
else {
return null;
public void applyFilters(
QuerySpec querySpec,
FilterAliasGenerator aliasGenerator,
Map<String, Filter> enabledFilters) {
final FilterPredicate predicate = generateFilterPredicate( aliasGenerator, enabledFilters );
if ( predicate != null ) {
querySpec.applyPredicate( predicate );
}
}
public static FilterPredicate doCreateFilterPredicate(String filterFragment, Map<String, Filter> enabledFilters) {
final Matcher matcher = FILTER_PARAMETER_PATTERN.matcher( filterFragment );
final StringBuilder sb = new StringBuilder();
int pos = 0;
final List<FilterJdbcParameter> parameters = new ArrayList<>( matcher.groupCount() );
while( matcher.find() ) {
sb.append( filterFragment, pos, matcher.start() );
pos = matcher.end();
sb.append( "?" );
final String filterName = matcher.group( 1 );
final String parameterName = matcher.group( 2 );
public FilterPredicate generateFilterPredicate(FilterAliasGenerator aliasGenerator, Map<String, Filter> enabledFilters) {
final FilterPredicate filterPredicate = new FilterPredicate();
for ( int i = 0, max = filterNames.length; i < max; i++ ) {
final String filterName = filterNames[i];
final FilterImpl enabledFilter = (FilterImpl) enabledFilters.get( filterName );
if ( enabledFilter == null ) {
throw new MappingException( String.format( "unknown filter [%s]", filterName ) );
}
if ( enabledFilter != null ) {
String condition = render( aliasGenerator, i );
final List<String> filterParameterNames = parameterNames[i];
for ( int paramPos = 0; paramPos < filterParameterNames.size(); paramPos++ ) {
final String parameterName = filterParameterNames.get( paramPos );
final Type parameterType = enabledFilter.getFilterDefinition().getParameterType( parameterName );
if ( ! (parameterType instanceof JdbcMapping ) ) {
if ( ! (parameterType instanceof JdbcMapping) ) {
throw new MappingException( String.format( "parameter [%s] for filter [%s] is not of JdbcMapping type", parameterName, filterName ) );
}
final JdbcMapping jdbcMapping = (JdbcMapping) parameterType;
final Object parameterValue = enabledFilter.getParameter( parameterName );
if ( parameterValue == null ) {
throw new MappingException( String.format( "unknown parameter [%s] for filter [%s]", parameterName, filterName ) );
}
if ( parameterValue instanceof Iterable && !jdbcMapping.getJavaTypeDescriptor().isInstance( parameterValue ) ) {
final StringBuilder paramMarkers = new StringBuilder( "?" );
if ( parameterValue instanceof Iterable
&& !jdbcMapping.getJavaTypeDescriptor().isInstance( parameterValue ) ) {
final Iterator<?> iterator = ( (Iterable<?>) parameterValue ).iterator();
if ( iterator.hasNext() ) {
parameters.add( new FilterJdbcParameter( jdbcMapping, iterator.next() ) );
final Object value = iterator.next();
final FilterJdbcParameter jdbcParameter = new FilterJdbcParameter( jdbcMapping, value );
filterPredicate.applyParameter( jdbcParameter );
while ( iterator.hasNext() ) {
sb.append( ",?" );
parameters.add( new FilterJdbcParameter( jdbcMapping, iterator.next() ) );
paramMarkers.append( ",?" );
filterPredicate.applyParameter( new FilterJdbcParameter( jdbcMapping, iterator.next() ) );
}
}
else {
// We need a dummy value if the list is empty
parameters.add( new FilterJdbcParameter( jdbcMapping, null ) );
filterPredicate.applyParameter( new FilterJdbcParameter( jdbcMapping, null ) );
}
}
else {
parameters.add( new FilterJdbcParameter( jdbcMapping, parameterValue ) );
filterPredicate.applyParameter( new FilterJdbcParameter( jdbcMapping, parameterValue ) );
}
final String marker = ":" + filterNames[ i ] + "." + parameterName;
condition = condition.replaceAll( marker, paramMarkers.toString() );
}
filterPredicate.applyFragment( condition );
}
}
sb.append( filterFragment, pos, filterFragment.length() );
return new FilterPredicate( sb.toString(), parameters );
if ( filterPredicate.isEmpty() ) {
return null;
}
return filterPredicate;
}
}

View File

@ -40,6 +40,8 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.Restrictable;
import org.hibernate.metamodel.mapping.Restrictable.RestrictionPredicatePartType;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
@ -363,12 +365,18 @@ public class LoaderSelectBuilder {
}
private SelectStatement generateSelect() {
final Restrictable restrictable;
if ( loadable instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) loadable;
restrictable = (Restrictable) pluralAttributeMapping.getCollectionDescriptor();
if ( pluralAttributeMapping.getMappedType().getCollectionSemantics() instanceof BagSemantics ) {
currentBagRole = pluralAttributeMapping.getNavigableRole().getNavigableName();
}
}
else {
restrictable = (Restrictable) loadable;
}
final NavigablePath rootNavigablePath = new NavigablePath( loadable.getRootPathName() );
final QuerySpec rootQuerySpec = new QuerySpec( true );
@ -393,6 +401,15 @@ public class LoaderSelectBuilder {
creationContext
);
restrictable.applyRestrictions(
(predicate, partType, sourceType) -> rootQuerySpec.applyPredicate( predicate ),
rootTableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
Collections.emptySet(),
sqlAstCreationState.getFromClauseAccess()
);
rootQuerySpec.getFromClause().addRoot( rootTableGroup );
sqlAstCreationState.getFromClauseAccess().registerTableGroup( rootNavigablePath, rootTableGroup );
registerPluralTableGroupParts( sqlAstCreationState.getFromClauseAccess(), rootTableGroup );
@ -473,12 +490,8 @@ public class LoaderSelectBuilder {
if ( loadable instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) loadable;
applyFiltering( rootQuerySpec, rootTableGroup, pluralAttributeMapping, sqlAstCreationState.getFromClauseAccess() );
applyOrdering( rootTableGroup, pluralAttributeMapping );
}
else if ( loadable instanceof Joinable ) {
applyFiltering( rootQuerySpec, rootTableGroup, (Joinable) loadable, sqlAstCreationState.getFromClauseAccess() );
}
if ( orderByFragments != null ) {
orderByFragments.forEach(
@ -588,7 +601,30 @@ public class LoaderSelectBuilder {
final CollectionPersister collectionPersister = pluralAttributeMapping.getCollectionDescriptor();
final Joinable joinable = collectionPersister.getCollectionType().getAssociatedJoinable( creationContext.getSessionFactory() );
joinable.applyRestrictions(
querySpec,
(predicate,partType,sourceType) -> {
if ( partType == RestrictionPredicatePartType.COLLECTION ) {
querySpec.applyPredicate( predicate );
}
else if ( partType == RestrictionPredicatePartType.MANY_TO_MANY ) {
final NavigablePath parentNavigablePath = tableGroup.getNavigablePath().getParent();
if ( parentNavigablePath == null ) {
querySpec.applyPredicate( predicate );
}
else {
final TableGroup parentTableGroup = fromClauseAccess.getTableGroup( parentNavigablePath );
TableGroupJoin pluralTableGroupJoin = null;
for ( TableGroupJoin nestedTableGroupJoin : parentTableGroup.getTableGroupJoins() ) {
if ( nestedTableGroupJoin.getNavigablePath() == tableGroup.getNavigablePath() ) {
pluralTableGroupJoin = nestedTableGroupJoin;
break;
}
}
assert pluralTableGroupJoin != null;
pluralTableGroupJoin.applyPredicate( predicate );
}
}
},
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),

View File

@ -14,9 +14,11 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.Filter;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.loader.ast.spi.Loadable;
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
import org.hibernate.loader.ast.spi.NaturalIdLoader;
@ -37,6 +39,7 @@ import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
@ -493,4 +496,10 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
default int getNumberOfFetchables() {
return getEntityPersister().getNumberOfFetchables();
}
FilterPredicate generateFilterPredicate(
TableGroup tableGroup,
boolean useQualifier,
Set<String> treatAsDeclarations,
Map<String, Filter> enabledFilters);
}

View File

@ -0,0 +1,72 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping;
import java.util.Map;
import java.util.Set;
import org.hibernate.Filter;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* Things that can have {@link org.hibernate.annotations.Where}
* and {@link org.hibernate.annotations.Filter} applied to them -
* entities and collections
*/
public interface Restrictable {
/**
* Apply {@link org.hibernate.annotations.Filter} and
* {@link org.hibernate.annotations.Where} restrictions
*/
void applyRestrictions(
QuerySpec querySpec,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
FromClauseAccess fromClauseAccess);
/**
* Apply {@link org.hibernate.annotations.Filter} and
* {@link org.hibernate.annotations.Where} restrictions
*/
void applyRestrictions(
RestrictionPredicateConsumer predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
FromClauseAccess fromClauseAccess);
enum RestrictionPredicatePartType {
ENTITY,
COLLECTION,
MANY_TO_MANY,
ONE_TO_MANY
}
enum RestrictionSourceType {
/**
* {@link org.hibernate.annotations.Where}
*/
WHERE,
/**
* {@link org.hibernate.annotations.Filter}
*/
FILTER
}
@FunctionalInterface
interface RestrictionPredicateConsumer {
void consume(Predicate predicate, Joinable.RestrictionPredicatePartType partType, Joinable.RestrictionSourceType sourceType);
}
}

View File

@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
@ -119,7 +120,7 @@ import org.hibernate.sql.ast.tree.expression.AliasedExpression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
import org.hibernate.sql.ast.tree.select.SelectStatement;
@ -134,7 +135,11 @@ import org.hibernate.type.Type;
import org.jboss.logging.Logger;
import static org.hibernate.internal.FilterHelper.doCreateFilterPredicate;
import static org.hibernate.metamodel.mapping.Restrictable.RestrictionPredicatePartType.COLLECTION;
import static org.hibernate.metamodel.mapping.Restrictable.RestrictionPredicatePartType.MANY_TO_MANY;
import static org.hibernate.metamodel.mapping.Restrictable.RestrictionPredicatePartType.ONE_TO_MANY;
import static org.hibernate.metamodel.mapping.Restrictable.RestrictionSourceType.FILTER;
import static org.hibernate.metamodel.mapping.Restrictable.RestrictionSourceType.WHERE;
/**
* Base implementation of the <tt>QueryableCollection</tt> interface.
@ -2036,47 +2041,71 @@ public abstract class AbstractCollectionPersister
applyOneToManyWhereRestriction( alias, tableGroup, querySpec, tableGroupJoin );
}
/**
* Apply both {@link org.hibernate.annotations.Filter} and
* {@link org.hibernate.annotations.Where} restrictions
*/
@Override
public void applyRestrictions(
RestrictionPredicateConsumer predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
FromClauseAccess fromClauseAccess) {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// handle `@Filter`
applyFilterRestrictions( predicateConsumer, tableGroup, enabledFilters, fromClauseAccess );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// handle `@Where`
TableReference tableReference;
if ( isManyToMany() ) {
tableReference = tableGroup.getPrimaryTableReference();
}
else if ( elementPersister instanceof Joinable ) {
tableReference = tableGroup.getTableReference( tableGroup.getNavigablePath(), ( (Joinable) elementPersister ).getTableName() );
}
else {
tableReference = tableGroup.getTableReference( tableGroup.getNavigablePath(), qualifiedTableName );
}
final String alias;
if ( tableReference == null ) {
alias = null;
}
else if ( useQualifier && tableReference.getIdentificationVariable() != null ) {
alias = tableReference.getIdentificationVariable();
}
else {
alias = tableReference.getTableExpression();
}
applyWhereRestriction( alias, (predicate) -> predicateConsumer.consume( predicate, COLLECTION, WHERE ) );
applyManyToManyWhereRestriction( tableGroup, (predicate) -> predicateConsumer.consume( predicate, MANY_TO_MANY, WHERE ) );
applyOneToManyWhereRestriction( alias, tableGroup, (predicate) -> predicateConsumer.consume( predicate, ONE_TO_MANY, WHERE ) );
}
protected void applyFilterRestrictions(
QuerySpec querySpec,
TableGroup tableGroup,
Map<String, Filter> enabledFilters,
TableGroupJoin pluralTableGroupJoin) {
if ( filterHelper != null ) {
final StringBuilder fragment = new StringBuilder();
filterHelper.render( fragment, getFilterAliasGenerator( tableGroup ), enabledFilters );
if ( fragment.length() > 1 ) {
final FilterPredicate filterPredicate = doCreateFilterPredicate( fragment.toString(), enabledFilters );
if ( pluralTableGroupJoin == null ) {
querySpec.applyPredicate( filterPredicate );
}
else {
pluralTableGroupJoin.applyPredicate( filterPredicate );
}
}
filterHelper.applyFilters( querySpec, getFilterAliasGenerator( tableGroup ), enabledFilters );
}
if ( manyToManyFilterHelper != null ) {
assert elementPersister instanceof Joinable;
assert isManyToMany();
final StringBuilder fragment = new StringBuilder();
manyToManyFilterHelper.render( fragment, elementPersister.getFilterAliasGenerator( tableGroup ), enabledFilters );
if ( fragment.length() > 1 ) {
final FilterPredicate filterPredicate = doCreateFilterPredicate( fragment.toString(), enabledFilters );
if ( pluralTableGroupJoin == null ) {
querySpec.applyPredicate( filterPredicate );
}
else {
pluralTableGroupJoin.applyPredicate( filterPredicate );
}
}
}
}
private static TableGroupJoin findTableGroupJoin(TableGroup tableGroup, FromClauseAccess fromClauseAccess) {
final NavigablePath parentNavigablePath;
if ( tableGroup == null || ( parentNavigablePath = tableGroup.getNavigablePath().getParent() ) == null ) {
return null;
manyToManyFilterHelper.applyFilters(
getFilterAliasGenerator( tableGroup ),
enabledFilters,
(predicate) -> {
final NavigablePath parentNavigablePath = tableGroup.getNavigablePath().getParent();
if ( parentNavigablePath == null ) {
querySpec.applyPredicate( predicate );
}
else {
final TableGroup parentTableGroup = fromClauseAccess.getTableGroup( parentNavigablePath );
@ -2088,6 +2117,37 @@ public abstract class AbstractCollectionPersister
}
}
assert pluralTableGroupJoin != null;
pluralTableGroupJoin.applyPredicate( predicate );
}
}
);
}
}
protected void applyFilterRestrictions(
RestrictionPredicateConsumer predicateConsumer,
TableGroup tableGroup,
Map<String, Filter> enabledFilters,
FromClauseAccess fromClauseAccess) {
if ( filterHelper != null ) {
filterHelper.applyFilters(
getFilterAliasGenerator( tableGroup ),
enabledFilters,
(filterPredicate) -> predicateConsumer.consume( filterPredicate, COLLECTION, FILTER )
);
}
if ( manyToManyFilterHelper != null ) {
assert elementPersister instanceof Joinable;
assert isManyToMany();
final TableReference tableReference = tableGroup.resolveTableReference( ( (Joinable) elementPersister ).getTableName() );
manyToManyFilterHelper.applyFilters(
getFilterAliasGenerator( tableReference.getIdentificationVariable() ),
enabledFilters,
(filterPredicate) -> predicateConsumer.consume( filterPredicate, MANY_TO_MANY, FILTER )
);
assert pluralTableGroupJoin != null;
return pluralTableGroupJoin;
}
@ -2097,16 +2157,14 @@ public abstract class AbstractCollectionPersister
String alias,
QuerySpec querySpec,
TableGroupJoin pluralTableGroupJoin) {
applyWhereRestriction( alias, querySpec::applyPredicate );
}
protected void applyWhereRestriction(String alias, Consumer<Predicate> predicateConsumer) {
if ( sqlWhereString != null ) {
final String whereCondition = getSQLWhereString( alias );
assert whereCondition != null;
final WhereFilterPredicate filterPredicate = new WhereFilterPredicate( whereCondition );
if ( pluralTableGroupJoin == null ) {
querySpec.applyPredicate( filterPredicate );
}
else {
pluralTableGroupJoin.applyPredicate( filterPredicate );
}
predicateConsumer.accept( new WhereFilterPredicate( whereCondition ) );
}
}
@ -2114,6 +2172,10 @@ public abstract class AbstractCollectionPersister
TableGroup tableGroup,
QuerySpec querySpec,
TableGroupJoin pluralTableGroupJoin) {
applyManyToManyWhereRestriction( tableGroup, querySpec::applyPredicate );
}
public void applyManyToManyWhereRestriction(TableGroup tableGroup, Consumer<Predicate> predicateConsumer) {
if ( manyToManyWhereString == null ) {
return;
}
@ -2121,13 +2183,7 @@ public abstract class AbstractCollectionPersister
final TableReference tableReference = tableGroup.resolveTableReference( ( (Joinable) elementPersister ).getTableName() );
final String condition = StringHelper.replace( manyToManyWhereTemplate, Template.TEMPLATE, tableReference.getIdentificationVariable() );
assert StringHelper.isNotEmpty( condition );
final WhereFilterPredicate filterPredicate = new WhereFilterPredicate( condition );
if ( pluralTableGroupJoin == null ) {
querySpec.applyPredicate( filterPredicate );
}
else {
pluralTableGroupJoin.applyPredicate( filterPredicate );
}
predicateConsumer.accept( new WhereFilterPredicate( condition ) );
}
private void applyOneToManyWhereRestriction(
@ -2135,6 +2191,10 @@ public abstract class AbstractCollectionPersister
TableGroup tableGroup,
QuerySpec querySpec,
TableGroupJoin pluralTableGroupJoin) {
applyOneToManyWhereRestriction( alias, tableGroup, querySpec::applyPredicate );
}
private void applyOneToManyWhereRestriction(String alias, TableGroup tableGroup, Consumer<Predicate> predicateConsumer) {
if ( ! isOneToMany() ) {
return;
}
@ -2145,13 +2205,7 @@ public abstract class AbstractCollectionPersister
final String associationWhereCondition = ( (Joinable) getElementPersister() ).oneToManyFilterFragment( alias, null );
if ( StringHelper.isNotEmpty( associationWhereCondition ) ) {
final WhereFilterPredicate filterPredicate = new WhereFilterPredicate( associationWhereCondition );
if ( pluralTableGroupJoin == null ) {
querySpec.applyPredicate( filterPredicate );
}
else {
pluralTableGroupJoin.applyPredicate( filterPredicate );
}
predicateConsumer.accept( new WhereFilterPredicate( associationWhereCondition ) );
}
}

View File

@ -268,8 +268,6 @@ import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.internal.FilterHelper.doCreateFilterPredicate;
/**
* Basic functionality for persisting an entity via JDBC
* through either generated or custom SQL
@ -1052,7 +1050,12 @@ public abstract class AbstractEntityPersister
propertyDefinedOnSubclass = ArrayHelper.toBooleanArray( definedBySubclass );
// Handle any filters applied to the class level
if ( CollectionHelper.isEmpty( bootDescriptor.getFilters() ) ) {
filterHelper = null;
}
else {
filterHelper = new FilterHelper( bootDescriptor.getFilters(), factory );
}
// Check if we can use Reference Cached entities in 2lc
// todo : should really validate that the cache access type is read-only
@ -1337,7 +1340,7 @@ public abstract class AbstractEntityPersister
creationContext
);
return new StandardTableGroup(
final StandardTableGroup tableGroup = new StandardTableGroup(
canUseInnerJoins,
navigablePath,
this,
@ -1346,10 +1349,10 @@ public abstract class AbstractEntityPersister
true,
sqlAliasBase,
(tableExpression) -> ArrayHelper.contains( getSubclassTableNames(), tableExpression ),
(tableExpression, tableGroup) -> {
(tableExpression, tg) -> {
final String[] subclassTableNames = getSubclassTableNames();
for ( int i = 0; i < subclassTableNames.length; i++ ) {
if ( tableExpression.equals( subclassTableNames[i] ) ) {
if ( tableExpression.equals( subclassTableNames[ i ] ) ) {
final boolean isNullableTable = isNullableSubclassTable( i );
final TableReference joinedTableReference = new TableReference(
tableExpression,
@ -1380,6 +1383,8 @@ public abstract class AbstractEntityPersister
},
getFactory()
);
return tableGroup;
}
@Override
@ -3992,6 +3997,10 @@ public abstract class AbstractEntityPersister
@Override
public String filterFragment(String alias, Map<String, Filter> enabledFilters, Set<String> treatAsDeclarations) {
if ( filterHelper == null ) {
return "";
}
final StringBuilder sessionFilterFragment = new StringBuilder();
filterHelper.render( sessionFilterFragment, alias == null ? null : getFilterAliasGenerator( alias ), enabledFilters );
final String filterFragment = filterFragment( alias, treatAsDeclarations );
@ -4007,6 +4016,10 @@ public abstract class AbstractEntityPersister
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
boolean useIdentificationVariable) {
if ( filterHelper == null ) {
return null;
}
final String alias;
if ( tableGroup == null ) {
alias = null;
@ -4017,6 +4030,7 @@ public abstract class AbstractEntityPersister
else {
alias = tableGroup.getPrimaryTableReference().getTableExpression();
}
final StringBuilder sessionFilterFragment = new StringBuilder();
filterHelper.render( sessionFilterFragment, !useIdentificationVariable || tableGroup == null ? null : getFilterAliasGenerator( tableGroup ), enabledFilters );
final String filterFragment = filterFragment( alias, treatAsDeclarations );
@ -4030,6 +4044,42 @@ public abstract class AbstractEntityPersister
return alias;
}
@Override
public void applyRestrictions(
RestrictionPredicateConsumer predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
FromClauseAccess fromClauseAccess) {
// handle `@Filter`
final FilterAliasGenerator aliasGenerator = useQualifier && tableGroup != null
? getFilterAliasGenerator( tableGroup )
: null;
applyFilterRestrictions(
enabledFilters,
aliasGenerator,
(predicate) -> predicateConsumer.consume( predicate, RestrictionPredicatePartType.ENTITY, RestrictionSourceType.FILTER )
);
// handle `@Where`
final String alias;
if ( tableGroup == null ) {
alias = null;
}
else if ( useQualifier && tableGroup.getPrimaryTableReference().getIdentificationVariable() != null ) {
alias = tableGroup.getPrimaryTableReference().getIdentificationVariable();
}
else {
alias = tableGroup.getPrimaryTableReference().getTableExpression();
}
applyWhereRestriction(
generateWhereConditionAlias( alias ),
treatAsDeclarations,
(predicate) -> predicateConsumer.consume( predicate, RestrictionPredicatePartType.ENTITY, RestrictionSourceType.WHERE )
);
}
/**
* Apply both {@link org.hibernate.annotations.Filter} and
* {@link org.hibernate.annotations.Where} restrictions
@ -4048,7 +4098,7 @@ public abstract class AbstractEntityPersister
final FilterAliasGenerator aliasGenerator = useQualifier && tableGroup != null
? getFilterAliasGenerator( tableGroup )
: null;
applyFilterRestrictions( querySpec, tableGroup, enabledFilters, aliasGenerator, tableGroupJoin );
applyFilterRestrictions( querySpec, enabledFilters, aliasGenerator, tableGroupJoin );
// handle `@Where`
final String alias;
@ -4064,22 +4114,31 @@ public abstract class AbstractEntityPersister
applyWhereRestriction( generateWhereConditionAlias( alias ), treatAsDeclarations, querySpec, tableGroupJoin );
}
@Override
public FilterPredicate generateFilterPredicate(TableGroup tableGroup, boolean useQualifier, Set<String> treatAsDeclarations, Map<String, Filter> enabledFilters) {
if ( filterHelper == null ) {
return null;
}
final FilterAliasGenerator aliasGenerator = useQualifier && tableGroup != null
? getFilterAliasGenerator( tableGroup )
: null;
return filterHelper.generateFilterPredicate( aliasGenerator, enabledFilters );
}
protected void applyFilterRestrictions(
QuerySpec querySpec,
TableGroup tableGroup,
Map<String, Filter> enabledFilters,
FilterAliasGenerator aliasGenerator,
TableGroupJoin tableGroupJoin) {
final StringBuilder fragment = new StringBuilder();
filterHelper.render( fragment, aliasGenerator, enabledFilters );
if ( fragment.length() > 1 ) {
final FilterPredicate filterPredicate = doCreateFilterPredicate( fragment.toString(), enabledFilters );
if ( tableGroupJoin == null ) {
querySpec.applyPredicate( filterPredicate );
FilterAliasGenerator aliasGenerator) {
if ( filterHelper != null ) {
filterHelper.applyFilters( querySpec, aliasGenerator, enabledFilters );
}
else {
tableGroupJoin.applyPredicate( filterPredicate );
}
protected void applyFilterRestrictions(
Map<String, Filter> enabledFilters, FilterAliasGenerator aliasGenerator, Consumer<Predicate> predicateConsumer) {
if ( filterHelper != null ) {
filterHelper.applyFilters( aliasGenerator, enabledFilters, (Consumer) predicateConsumer );
}
}
@ -4116,6 +4175,13 @@ public abstract class AbstractEntityPersister
}
}
protected void applyWhereRestriction(String alias, Set<String> treatAsDeclarations, Consumer<Predicate> predicateConsumer) {
if ( hasWhere() ) {
final String whereCondition = getSQLWhereString( alias );
predicateConsumer.accept( new WhereFilterPredicate( whereCondition ) );
}
}
public String generateFilterConditionAlias(String rootAlias) {
return rootAlias;
}
@ -4398,7 +4464,7 @@ public abstract class AbstractEntityPersister
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers loadQueryInfluencers) {
if ( loadQueryInfluencers.hasEnabledFilters() ) {
if ( loadQueryInfluencers.hasEnabledFilters() && filterHelper != null ) {
if ( filterHelper.isAffectedBy( loadQueryInfluencers.getEnabledFilters() ) ) {
return true;
}

View File

@ -5,15 +5,15 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.persister.entity;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.hibernate.Filter;
import org.hibernate.MappingException;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.metamodel.mapping.Restrictable;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* Anything that can be loaded by outer join - namely
@ -21,7 +21,7 @@ import org.hibernate.sql.ast.tree.select.QuerySpec;
*
* @author Gavin King
*/
public interface Joinable {
public interface Joinable extends Restrictable {
//should this interface extend PropertyMapping?
/**
@ -38,18 +38,6 @@ public interface Joinable {
*/
public String[] getKeyColumnNames();
/**
* Apply {@link org.hibernate.annotations.Filter} and
* {@link org.hibernate.annotations.Where} restrictions
*/
void applyRestrictions(
QuerySpec querySpec,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
FromClauseAccess fromClauseAccess);
/**
* Get the where clause filter, given a query alias and considering enabled session filters
*/

View File

@ -116,15 +116,13 @@ public class MatchingIdSelectionHelper {
);
sqmConverter.getProcessingStateStack().pop();
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
executionContext.getSession().getLoadQueryInfluencers(),
(Joinable) targetEntityDescriptor.getEntityPersister(),
mutatingTableGroup
final FilterPredicate filterPredicate = targetEntityDescriptor.getEntityPersister().generateFilterPredicate(
mutatingTableGroup,
true,
Collections.emptySet(),
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters()
);
if ( filterPredicate != null ) {
restriction = SqlAstTreeHelper.combinePredicates( restriction, filterPredicate );
}
idSelectionQuery.applyPredicate( restriction );
idSelectionQuery.applyPredicate( SqlAstTreeHelper.combinePredicates( restriction, filterPredicate ) );
return new SelectStatement( idSelectionQuery, domainResults );
}

View File

@ -156,10 +156,11 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
}
);
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
executionContext.getSession().getLoadQueryInfluencers(),
(Joinable) entityDescriptor,
deletingTableGroup
final FilterPredicate filterPredicate = entityDescriptor.generateFilterPredicate(
deletingTableGroup,
true,
Collections.emptySet(),
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters()
);
if ( filterPredicate != null ) {
needsIdTableWrapper.setValue( true );

View File

@ -186,10 +186,11 @@ public class TableBasedUpdateHandler
assert predicate != null;
}
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
executionContext.getSession().getLoadQueryInfluencers(),
(Joinable) rootEntityDescriptor,
updatingTableGroup
final FilterPredicate filterPredicate = entityDescriptor.generateFilterPredicate(
updatingTableGroup,
true,
Collections.emptySet(),
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters()
);
if ( filterPredicate != null ) {
predicate = SqlAstTreeHelper.combinePredicates( predicate, filterPredicate );

View File

@ -26,7 +26,6 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.persistence.TemporalType;
import org.hibernate.HibernateException;
import org.hibernate.Internal;
@ -47,7 +46,6 @@ import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator;
import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.internal.FilterHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
@ -62,6 +60,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.Bindable;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.ConvertibleModelPart;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
@ -70,18 +69,18 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.Restrictable;
import org.hibernate.metamodel.mapping.Restrictable.RestrictionPredicatePartType;
import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.metamodel.mapping.ValueMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.ExplicitColumnDiscriminatorMappingImpl;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
@ -121,6 +120,8 @@ import org.hibernate.query.QueryLogging;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TemporalUnit;
import org.hibernate.query.UnaryArithmeticOperator;
import org.hibernate.query.criteria.JpaPath;
import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
@ -131,8 +132,10 @@ import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression;
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
import org.hibernate.query.sqm.sql.internal.BasicValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.DiscriminatedAssociationPathInterpretation;
@ -148,6 +151,7 @@ import org.hibernate.query.sqm.sql.internal.SqmMapEntryResult;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
import org.hibernate.query.sqm.sql.internal.TypeHelper;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.cte.SqmCteContainer;
@ -160,6 +164,8 @@ import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedRootJoin;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
@ -171,6 +177,7 @@ import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedRoot;
import org.hibernate.query.sqm.tree.expression.Conversion;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
@ -195,6 +202,7 @@ import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
@ -213,6 +221,7 @@ import org.hibernate.query.sqm.tree.from.SqmFromClause;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
@ -289,16 +298,21 @@ import org.hibernate.sql.ast.tree.expression.ExtractUnit;
import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression;
import org.hibernate.sql.ast.tree.expression.Over;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression;
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Star;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
import org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup;
import org.hibernate.sql.ast.tree.from.CorrelatedTableGroup;
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
import org.hibernate.sql.ast.tree.from.PluralTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
@ -331,6 +345,7 @@ import org.hibernate.sql.ast.tree.update.Assignment;
import org.hibernate.sql.ast.tree.update.UpdateStatement;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.internal.JdbcParametersImpl;
import org.hibernate.sql.exec.internal.VersionTypeSeedParameterSpecification;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParameters;
@ -352,6 +367,8 @@ import org.hibernate.usertype.UserVersionType;
import org.jboss.logging.Logger;
import jakarta.persistence.TemporalType;
import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues;
import static org.hibernate.query.BinaryArithmeticOperator.ADD;
import static org.hibernate.query.BinaryArithmeticOperator.MULTIPLY;
@ -391,7 +408,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private ForeignKeyDescriptor.Nature currentlyResolvingForeignKeySide;
private SqmQueryPart<?> currentSqmQueryPart;
private Map<String, FilterPredicate> collectionFilterPredicates;
private final Map<String, List<Predicate>> collectionFilterPredicates = new HashMap<>();
private List<Map.Entry<OrderByFragment, TableGroup>> orderByFragments;
private final SqlAliasBaseManager sqlAliasBaseManager = new SqlAliasBaseManager();
@ -670,12 +687,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final List<Assignment> assignments = visitSetClause( sqmStatement.getSetClause() );
addVersionedAssignment( assignments::add, sqmStatement );
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
(Joinable) entityDescriptor,
final FilterPredicate filterPredicate = entityDescriptor.generateFilterPredicate(
rootTableGroup,
// todo (6.0): this is temporary until we implement proper alias support
AbstractSqlAstTranslator.rendersTableReferenceAlias( Clause.UPDATE )
AbstractSqlAstTranslator.rendersTableReferenceAlias( Clause.UPDATE ),
Collections.emptySet(),
loadQueryInfluencers.getEnabledFilters()
);
if ( filterPredicate != null ) {
additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, filterPredicate );
@ -900,12 +916,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
throw new HibernateException( "Not expecting multiple table references for an SQM DELETE" );
}
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
(Joinable) entityDescriptor,
final FilterPredicate filterPredicate = entityDescriptor.generateFilterPredicate(
rootTableGroup,
// todo (6.0): this is temporary until we implement proper alias support
AbstractSqlAstTranslator.rendersTableReferenceAlias( Clause.DELETE )
AbstractSqlAstTranslator.rendersTableReferenceAlias( Clause.DELETE ),
Collections.emptySet(),
loadQueryInfluencers.getEnabledFilters()
);
if ( filterPredicate != null ) {
additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, filterPredicate );
@ -1747,22 +1762,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final ModelPartContainer modelPartContainer = root.getModelPart();
final EntityPersister entityPersister = modelPartContainer.findContainingEntityMapping().getEntityPersister();
assert entityPersister instanceof Joinable;
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(), (Joinable) entityPersister, root
);
if ( filterPredicate != null ) {
sqlQuerySpec.applyPredicate( filterPredicate );
}
if ( CollectionHelper.isNotEmpty( collectionFilterPredicates ) ) {
root.getTableGroupJoins().forEach(
tableGroupJoin -> {
collectionFilterPredicates.forEach( (alias, predicate) -> {
root.getTableGroupJoins().forEach( (tableGroupJoin) -> {
collectionFilterPredicates.forEach( (alias, predicates) -> {
if ( tableGroupJoin.getJoinedGroup().getGroupAlias().equals( alias ) ) {
tableGroupJoin.applyPredicate( predicate );
if ( CollectionHelper.isNotEmpty( predicates ) ) {
predicates.forEach( tableGroupJoin::applyPredicate );
}
}
} );
}
);
} );
}
}
}
@ -2319,14 +2329,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
this,
creationContext
);
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
(Joinable) entityDescriptor,
tableGroup
( (Restrictable) entityDescriptor ).applyRestrictions(
currentQuerySpec,
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
Collections.emptySet(),
getFromClauseAccess()
);
if ( filterPredicate != null ) {
currentQuerySpec.applyPredicate( filterPredicate );
}
}
log.tracef( "Resolved SqmRoot [%s] to new TableGroup [%s]", sqmRoot, tableGroup );
@ -3242,14 +3253,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
this,
creationContext
);
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
(Joinable) pluralAttributeMapping.getCollectionDescriptor(),
tableGroup
( (Joinable) pluralAttributeMapping.getCollectionDescriptor() ).applyRestrictions(
subQuerySpec,
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
Collections.emptySet(),
getFromClauseAccess()
);
if ( filterPredicate != null ) {
subQuerySpec.applyPredicate( filterPredicate );
}
getFromClauseAccess().registerTableGroup( pluralPath.getNavigablePath(), tableGroup );
registerPluralTableGroupParts( tableGroup );
@ -3385,14 +3397,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
this,
creationContext
);
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
(Joinable) pluralAttributeMapping.getCollectionDescriptor(),
tableGroup
( (Joinable) pluralAttributeMapping.getCollectionDescriptor() ).applyRestrictions(
subQuerySpec,
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
Collections.emptySet(),
getFromClauseAccess()
);
if ( filterPredicate != null ) {
subQuerySpec.applyPredicate( filterPredicate );
}
getFromClauseAccess().registerTableGroup( pluralPartPath.getNavigablePath(), tableGroup );
registerPluralTableGroupParts( tableGroup );
@ -5023,14 +5036,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
this,
creationContext
);
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
(Joinable) pluralAttributeMapping.getCollectionDescriptor(),
tableGroup
( (Joinable) pluralAttributeMapping.getCollectionDescriptor() ).applyRestrictions(
subQuerySpec,
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
Collections.emptySet(),
getFromClauseAccess()
);
if ( filterPredicate != null ) {
subQuerySpec.applyPredicate( filterPredicate );
}
getFromClauseAccess().registerTableGroup( pluralPath.getNavigablePath(), tableGroup );
registerPluralTableGroupParts( tableGroup );
@ -5661,31 +5675,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( fetchable instanceof PluralAttributeMapping && fetch.getTiming() == FetchTiming.IMMEDIATE && joined ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable;
final Joinable joinable = pluralAttributeMapping
.getCollectionDescriptor()
.getCollectionType()
.getAssociatedJoinable( getCreationContext().getSessionFactory() );
final TableGroup tableGroup = getFromClauseIndex().getTableGroup( fetchablePath );
final FilterPredicate collectionFieldFilterPredicate = FilterHelper.createFilterPredicate(
getLoadQueryInfluencers(),
joinable,
tableGroup
);
if ( collectionFieldFilterPredicate != null ) {
if ( collectionFilterPredicates == null ) {
collectionFilterPredicates = new HashMap<>();
( (Restrictable) pluralAttributeMapping.getCollectionDescriptor() ).applyRestrictions(
(predicate, partType, sourceType) -> {
if ( partType == RestrictionPredicatePartType.COLLECTION ) {
addCollectionFilterPredicate( tableGroup.getGroupAlias(), predicate );
}
collectionFilterPredicates.put( tableGroup.getGroupAlias(), collectionFieldFilterPredicate );
}
if ( pluralAttributeMapping.getCollectionDescriptor().isManyToMany() ) {
assert joinable instanceof CollectionPersister;
final Predicate manyToManyFilterPredicate = FilterHelper.createManyToManyFilterPredicate(
getLoadQueryInfluencers(),
( CollectionPersister) joinable,
tableGroup
);
if ( manyToManyFilterPredicate != null ) {
else if ( partType == RestrictionPredicatePartType.MANY_TO_MANY ) {
final TableGroup parentTableGroup = getFromClauseIndex().getTableGroup( fetchParent.getNavigablePath() );
TableGroupJoin pluralTableGroupJoin = null;
for ( TableGroupJoin nestedTableGroupJoin : parentTableGroup.getTableGroupJoins() ) {
@ -5696,9 +5693,18 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
assert pluralTableGroupJoin != null;
pluralTableGroupJoin.applyPredicate( manyToManyFilterPredicate );
pluralTableGroupJoin.applyPredicate( predicate );
}
else if ( partType == RestrictionPredicatePartType.ONE_TO_MANY ) {
addCollectionFilterPredicate( tableGroup.getGroupAlias(), predicate );
}
},
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
Collections.emptySet(),
getFromClauseAccess()
);
if ( currentQuerySpec().isRoot() ) {
assert tableGroup.getModelPart() == pluralAttributeMapping;
@ -5721,6 +5727,18 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
private void addCollectionFilterPredicate(String groupAlias, Predicate predicate) {
final List<Predicate> existing = collectionFilterPredicates.get( groupAlias );
if ( existing != null ) {
existing.add( predicate );
}
else {
final ArrayList<Predicate> list = new ArrayList<>();
list.add( predicate );
collectionFilterPredicates.put( groupAlias, list );
}
}
private void applyOrdering(TableGroup tableGroup, PluralAttributeMapping pluralAttributeMapping) {
if ( pluralAttributeMapping.getOrderByFragment() != null ) {
applyOrdering( tableGroup, pluralAttributeMapping.getOrderByFragment() );

View File

@ -157,6 +157,7 @@ public interface SqlAstWalker {
void visitBetweenPredicate(BetweenPredicate betweenPredicate);
void visitFilterPredicate(FilterPredicate filterPredicate);
void visitFilterFragmentPredicate(FilterPredicate.FilterFragmentPredicate fragmentPredicate);
void visitWhereFilterPredicate(WhereFilterPredicate whereFilterPredicate);

View File

@ -4279,14 +4279,22 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override
public void visitFilterPredicate(FilterPredicate filterPredicate) {
assert StringHelper.isNotEmpty( filterPredicate.getFilterFragment() );
appendSql( filterPredicate.getFilterFragment() );
for ( FilterJdbcParameter filterJdbcParameter : filterPredicate.getFilterJdbcParameters() ) {
visitJunction( filterPredicate.getFragments() );
final List<FilterJdbcParameter> parameters = filterPredicate.getParameters();
if ( parameters != null ) {
for ( FilterJdbcParameter filterJdbcParameter : parameters ) {
parameterBinders.add( filterJdbcParameter.getBinder() );
jdbcParameters.addParameter( filterJdbcParameter.getParameter() );
filterJdbcParameters.add( filterJdbcParameter );
}
}
}
@Override
public void visitFilterFragmentPredicate(FilterPredicate.FilterFragmentPredicate fragmentPredicate) {
appendSql( fragmentPredicate.getSqlFragment() );
}
@Override
public void visitWhereFilterPredicate(WhereFilterPredicate whereFilterPredicate) {

View File

@ -447,6 +447,10 @@ public class AbstractSqlAstWalker implements SqlAstWalker {
public void visitFilterPredicate(FilterPredicate filterPredicate) {
}
@Override
public void visitFilterFragmentPredicate(FilterPredicate.FilterFragmentPredicate fragmentPredicate) {
}
@Override
public void visitWhereFilterPredicate(WhereFilterPredicate whereFilterPredicate) {
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.sql.ast.tree.predicate;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.internal.FilterJdbcParameter;
@ -21,17 +22,30 @@ import org.hibernate.sql.ast.SqlAstWalker;
* @author Nathan Xu
*/
public class FilterPredicate implements Predicate {
private final String filterFragment;
private final List<FilterJdbcParameter> filterJdbcParameters;
private Junction fragments = new Junction();
private List<FilterJdbcParameter> parameters;
public FilterPredicate(String filterFragment, List<FilterJdbcParameter> filterJdbcParameters) {
this.filterFragment = filterFragment;
this.filterJdbcParameters = filterJdbcParameters;
public FilterPredicate() {
}
public void applyFragment(FilterFragmentPredicate predicate) {
fragments.add( predicate );
}
public void applyFragment(String sqlFragment) {
fragments.add( new FilterFragmentPredicate( sqlFragment ) );
}
public void applyParameter(FilterJdbcParameter parameter) {
if ( parameters == null ) {
parameters = new ArrayList<>();
}
parameters.add( parameter );
}
@Override
public boolean isEmpty() {
return false;
return fragments.isEmpty();
}
@Override
@ -39,16 +53,43 @@ public class FilterPredicate implements Predicate {
sqlTreeWalker.visitFilterPredicate( this );
}
public String getFilterFragment() {
return filterFragment;
public Junction getFragments() {
return fragments;
}
public List<FilterJdbcParameter> getFilterJdbcParameters() {
return filterJdbcParameters;
public List<FilterJdbcParameter> getParameters() {
return parameters;
}
@Override
public JdbcMappingContainer getExpressionType() {
return null;
}
public static class FilterFragmentPredicate implements Predicate {
private final String sqlFragment;
public FilterFragmentPredicate(String sqlFragment) {
this.sqlFragment = sqlFragment;
}
public String getSqlFragment() {
return sqlFragment;
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitFilterFragmentPredicate( this );
}
@Override
public JdbcMappingContainer getExpressionType() {
return null;
}
@Override
public boolean isEmpty() {
return false;
}
}
}

View File

@ -31,6 +31,10 @@ public class Junction implements Predicate {
private final JdbcMappingContainer expressionType;
private final List<Predicate> predicates = new ArrayList<>();
public Junction() {
this( Nature.CONJUNCTION );
}
public Junction(Nature nature) {
this( nature, null );
}

View File

@ -11,6 +11,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.Filter;
@ -58,6 +59,7 @@ import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -703,6 +705,11 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
public JavaType getMappedJavaTypeDescriptor() {
return null;
}
@Override
public FilterPredicate generateFilterPredicate(TableGroup tableGroup, boolean useQualifier, Set<String> treatAsDeclarations, Map<String, Filter> enabledFilters) {
return null;
}
}
public static class NoopCollectionPersister implements CollectionPersister {

View File

@ -12,10 +12,12 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceException;
import org.hibernate.Filter;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
@ -58,6 +60,8 @@ import org.hibernate.persister.spi.PersisterClassResolver;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -717,6 +721,11 @@ public class PersisterClassProviderTest {
public JavaType getMappedJavaTypeDescriptor() {
return null;
}
@Override
public FilterPredicate generateFilterPredicate(TableGroup tableGroup, boolean useQualifier, Set<String> treatAsDeclarations, Map<String, Filter> enabledFilters) {
return null;
}
}
public static class GoofyException extends RuntimeException {

View File

@ -13,8 +13,10 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.Filter;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
@ -54,6 +56,8 @@ import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -818,4 +822,9 @@ public class CustomPersister implements EntityPersister {
public JavaType getMappedJavaTypeDescriptor() {
return null;
}
@Override
public FilterPredicate generateFilterPredicate(TableGroup tableGroup, boolean useQualifier, Set<String> treatAsDeclarations, Map<String, Filter> enabledFilters) {
return null;
}
}