HHH-16182 - Converted boolean values not always properly handled in predicates
This commit is contained in:
parent
51ef9f494b
commit
0c20980be2
|
@ -7,17 +7,25 @@
|
||||||
package org.hibernate.userguide.mapping.basic;
|
package org.hibernate.userguide.mapping.basic;
|
||||||
|
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
|
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||||
|
import org.hibernate.query.criteria.JpaPath;
|
||||||
|
import org.hibernate.query.criteria.JpaRoot;
|
||||||
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
|
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.Jira;
|
import org.hibernate.testing.orm.junit.Jira;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
|
@ -28,6 +36,7 @@ import jakarta.persistence.Table;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.isOneOf;
|
import static org.hamcrest.Matchers.isOneOf;
|
||||||
|
|
||||||
|
@ -97,22 +106,211 @@ public class BooleanMappingTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void createTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityOfBooleans entity = new EntityOfBooleans();
|
||||||
|
entity.id = 1;
|
||||||
|
assert !entity.convertedYesNo;
|
||||||
|
assert !entity.convertedTrueFalse;
|
||||||
|
assert !entity.convertedNumeric;
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void dropTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete EntityOfBooleans" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
||||||
public void testQueryLiteralUsage(SessionFactoryScope scope) {
|
public void testComparisonLiteralHandling(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( (session) -> {
|
scope.inTransaction( (session) -> {
|
||||||
session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = true" ).list();
|
assertThat(
|
||||||
session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = true" ).list();
|
session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = true" ).list(),
|
||||||
session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = true" ).list();
|
hasSize( 0 )
|
||||||
|
);
|
||||||
session.createMutationQuery( "delete EntityOfBooleans where convertedYesNo = true" ).executeUpdate();
|
assertThat(
|
||||||
session.createMutationQuery( "delete EntityOfBooleans where convertedTrueFalse = true" ).executeUpdate();
|
session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = true" ).list(),
|
||||||
session.createMutationQuery( "delete EntityOfBooleans where convertedNumeric = true" ).executeUpdate();
|
hasSize( 0 )
|
||||||
|
);
|
||||||
session.createMutationQuery( "update EntityOfBooleans set convertedYesNo = true" ).executeUpdate();
|
assertThat(
|
||||||
session.createMutationQuery( "update EntityOfBooleans set convertedTrueFalse = true" ).executeUpdate();
|
session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = true" ).list(),
|
||||||
session.createMutationQuery( "update EntityOfBooleans set convertedNumeric = true" ).executeUpdate();
|
hasSize( 0 )
|
||||||
|
);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = false" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = false" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = false" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo != true" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse != true" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric != true" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
||||||
|
public void testExpressionAsPredicateUsage(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo" ).list(),
|
||||||
|
hasSize( 0 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse" ).list(),
|
||||||
|
hasSize( 0 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric" ).list(),
|
||||||
|
hasSize( 0 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where (convertedYesNo)" ).list(),
|
||||||
|
hasSize( 0 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where (convertedTrueFalse)" ).list(),
|
||||||
|
hasSize( 0 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where (convertedNumeric)" ).list(),
|
||||||
|
hasSize( 0 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
||||||
|
public void testNegatedExpressionAsPredicateUsage(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where not convertedYesNo" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where not convertedTrueFalse" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where not convertedNumeric" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where not (convertedYesNo)" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where not (convertedTrueFalse)" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where not (convertedNumeric)" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
||||||
|
public void testSetClauseUsage(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createMutationQuery( "update EntityOfBooleans set convertedYesNo = true" ).executeUpdate(),
|
||||||
|
equalTo( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createMutationQuery( "update EntityOfBooleans set convertedTrueFalse = true" ).executeUpdate(),
|
||||||
|
equalTo( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createMutationQuery( "update EntityOfBooleans set convertedNumeric = true" ).executeUpdate(),
|
||||||
|
equalTo( 1 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric" ).list(),
|
||||||
|
hasSize( 1 )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
||||||
|
public void testCriteriaUsage(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat( countByCriteria( "convertedYesNo", true, session ), equalTo( 0 ) );
|
||||||
|
assertThat( countByCriteria( "convertedTrueFalse", true, session ), equalTo( 0 ) );
|
||||||
|
assertThat( countByCriteria( "convertedNumeric", true, session ), equalTo( 0 ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16182" )
|
||||||
|
public void testNegatedCriteriaUsage(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
assertThat( countByCriteria( "convertedYesNo", false, session ), equalTo( 1 ) );
|
||||||
|
assertThat( countByCriteria( "convertedTrueFalse", false, session ), equalTo( 1 ) );
|
||||||
|
assertThat( countByCriteria( "convertedNumeric", false, session ), equalTo( 1 ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private int countByCriteria(String attributeName, boolean matchValue, SessionImplementor session) {
|
||||||
|
final HibernateCriteriaBuilder builder = session.getCriteriaBuilder();
|
||||||
|
final JpaCriteriaQuery<Long> criteria = builder.createQuery( Long.class );
|
||||||
|
criteria.select( builder.count( builder.literal( 1 ) ) );
|
||||||
|
final JpaRoot<EntityOfBooleans> root = criteria.from( EntityOfBooleans.class );
|
||||||
|
final JpaPath<Boolean> convertedYesNo = root.get( attributeName );
|
||||||
|
if ( matchValue ) {
|
||||||
|
criteria.where( convertedYesNo );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
criteria.where( builder.not( convertedYesNo ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
final Long result = session.createQuery( criteria ).uniqueResult();
|
||||||
|
return result.intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = "EntityOfBooleans")
|
@Entity(name = "EntityOfBooleans")
|
||||||
|
|
|
@ -88,16 +88,12 @@ import org.hibernate.metamodel.mapping.internal.OneToManyCollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl;
|
import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||||
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
|
|
||||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
|
||||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||||
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
|
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
|
||||||
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPathSource;
|
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPathSource;
|
||||||
import org.hibernate.query.derived.AnonymousTupleTableGroupProducer;
|
|
||||||
import org.hibernate.query.derived.AnonymousTupleType;
|
|
||||||
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
||||||
import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
|
import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
|
||||||
import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPath;
|
import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPath;
|
||||||
|
@ -115,6 +111,8 @@ import org.hibernate.query.criteria.JpaCteCriteriaAttribute;
|
||||||
import org.hibernate.query.criteria.JpaPath;
|
import org.hibernate.query.criteria.JpaPath;
|
||||||
import org.hibernate.query.criteria.JpaSearchOrder;
|
import org.hibernate.query.criteria.JpaSearchOrder;
|
||||||
import org.hibernate.query.derived.AnonymousTupleEntityValuedModelPart;
|
import org.hibernate.query.derived.AnonymousTupleEntityValuedModelPart;
|
||||||
|
import org.hibernate.query.derived.AnonymousTupleTableGroupProducer;
|
||||||
|
import org.hibernate.query.derived.AnonymousTupleType;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
@ -392,6 +390,8 @@ import org.hibernate.type.CustomType;
|
||||||
import org.hibernate.type.EnumType;
|
import org.hibernate.type.EnumType;
|
||||||
import org.hibernate.type.JavaObjectType;
|
import org.hibernate.type.JavaObjectType;
|
||||||
import org.hibernate.type.SqlTypes;
|
import org.hibernate.type.SqlTypes;
|
||||||
|
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
|
||||||
|
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.java.TemporalJavaType;
|
import org.hibernate.type.descriptor.java.TemporalJavaType;
|
||||||
|
@ -501,6 +501,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
private boolean negativeAdjustment;
|
private boolean negativeAdjustment;
|
||||||
|
|
||||||
private final Set<AssociationKey> visitedAssociationKeys = new HashSet<>();
|
private final Set<AssociationKey> visitedAssociationKeys = new HashSet<>();
|
||||||
|
private final MappingMetamodel domainModel;
|
||||||
|
|
||||||
public BaseSqmToSqlAstConverter(
|
public BaseSqmToSqlAstConverter(
|
||||||
SqlAstCreationContext creationContext,
|
SqlAstCreationContext creationContext,
|
||||||
|
@ -569,8 +570,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
this.loadQueryInfluencers = loadQueryInfluencers;
|
this.loadQueryInfluencers = loadQueryInfluencers;
|
||||||
this.domainParameterXref = domainParameterXref;
|
this.domainParameterXref = domainParameterXref;
|
||||||
this.domainParameterBindings = domainParameterBindings;
|
this.domainParameterBindings = domainParameterBindings;
|
||||||
this.jpaCriteriaParamResolutions = domainParameterXref.getParameterResolutions()
|
this.jpaCriteriaParamResolutions = domainParameterXref.getParameterResolutions().getJpaCriteriaParamResolutions();
|
||||||
.getJpaCriteriaParamResolutions();
|
this.domainModel = creationContext.getSessionFactory().getRuntimeMetamodels().getMappingMetamodel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Boolean stackMatchHelper(SqlAstProcessingState processingState, SqlAstProcessingState c) {
|
private static Boolean stackMatchHelper(SqlAstProcessingState processingState, SqlAstProcessingState c) {
|
||||||
|
@ -4813,14 +4814,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
// A case wrapper for non-basic paths is not possible,
|
// A case wrapper for non-basic paths is not possible,
|
||||||
// because a case expression must return a scalar value,
|
// because a case expression must return a scalar value,
|
||||||
// so we instead add the type restriction predicate as conjunct
|
// so we instead add the type restriction predicate as conjunct
|
||||||
final MappingMetamodel domainModel = creationContext.getSessionFactory()
|
final String treatedName = treatedPath.getTreatTarget().getHibernateEntityName();
|
||||||
.getRuntimeMetamodels()
|
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( treatedName );
|
||||||
.getMappingMetamodel();
|
conjunctTreatUsages
|
||||||
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor(
|
.computeIfAbsent( wrappedPath, p -> new HashSet<>( 1 ) )
|
||||||
treatedPath.getTreatTarget().getHibernateEntityName()
|
.addAll( entityDescriptor.getSubclassEntityNames() );
|
||||||
);
|
|
||||||
conjunctTreatUsages.computeIfAbsent( wrappedPath, p -> new HashSet<>( 1 ) )
|
|
||||||
.addAll( entityDescriptor.getSubclassEntityNames() );
|
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
if ( wrappedPath instanceof DiscriminatorSqmPath ) {
|
if ( wrappedPath instanceof DiscriminatorSqmPath ) {
|
||||||
|
@ -4869,18 +4867,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate createTreatTypeRestriction(SqmPath<?> lhs, EntityDomainType<?> treatTarget) {
|
private Predicate createTreatTypeRestriction(SqmPath<?> lhs, EntityDomainType<?> treatTarget) {
|
||||||
final MappingMetamodel domainModel = creationContext.getSessionFactory()
|
|
||||||
.getRuntimeMetamodels()
|
|
||||||
.getMappingMetamodel();
|
|
||||||
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( treatTarget.getHibernateEntityName() );
|
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( treatTarget.getHibernateEntityName() );
|
||||||
final Set<String> subclassEntityNames = entityDescriptor.getSubclassEntityNames();
|
final Set<String> subclassEntityNames = entityDescriptor.getSubclassEntityNames();
|
||||||
return createTreatTypeRestriction( lhs, subclassEntityNames );
|
return createTreatTypeRestriction( lhs, subclassEntityNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate createTreatTypeRestriction(SqmPath<?> lhs, Set<String> subclassEntityNames) {
|
private Predicate createTreatTypeRestriction(SqmPath<?> lhs, Set<String> subclassEntityNames) {
|
||||||
final MappingMetamodel domainModel = creationContext.getSessionFactory()
|
|
||||||
.getRuntimeMetamodels()
|
|
||||||
.getMappingMetamodel();
|
|
||||||
// Do what visitSelfInterpretingSqmPath does, except for calling preparingReusablePath
|
// Do what visitSelfInterpretingSqmPath does, except for calling preparingReusablePath
|
||||||
// as that would register a type usage for the table group that we don't want here
|
// as that would register a type usage for the table group that we don't want here
|
||||||
final DiscriminatorSqmPath discriminatorSqmPath = (DiscriminatorSqmPath) lhs.type();
|
final DiscriminatorSqmPath discriminatorSqmPath = (DiscriminatorSqmPath) lhs.type();
|
||||||
|
@ -5264,25 +5256,31 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
if ( sqmExpression instanceof SqmParameter ) {
|
if ( sqmExpression instanceof SqmParameter ) {
|
||||||
return determineValueMapping( (SqmParameter<?>) sqmExpression );
|
return determineValueMapping( (SqmParameter<?>) sqmExpression );
|
||||||
}
|
}
|
||||||
else if ( sqmExpression instanceof SqmPath ) {
|
|
||||||
|
if ( sqmExpression instanceof SqmPath ) {
|
||||||
log.debugf( "Determining mapping-model type for SqmPath : %s ", sqmExpression );
|
log.debugf( "Determining mapping-model type for SqmPath : %s ", sqmExpression );
|
||||||
final MappingMetamodel domainModel = creationContext.getSessionFactory()
|
|
||||||
.getRuntimeMetamodels()
|
|
||||||
.getMappingMetamodel();
|
|
||||||
return SqmMappingModelHelper.resolveMappingModelExpressible(
|
return SqmMappingModelHelper.resolveMappingModelExpressible(
|
||||||
sqmExpression,
|
sqmExpression,
|
||||||
domainModel,
|
domainModel,
|
||||||
fromClauseIndex::findTableGroup
|
fromClauseIndex::findTableGroup
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( sqmExpression instanceof SqmBooleanExpressionPredicate ) {
|
||||||
|
final SqmBooleanExpressionPredicate expressionPredicate = (SqmBooleanExpressionPredicate) sqmExpression;
|
||||||
|
return determineValueMapping( expressionPredicate.getBooleanExpression(), fromClauseIndex );
|
||||||
|
}
|
||||||
|
|
||||||
// The model type of an enum literal is always inferred
|
// The model type of an enum literal is always inferred
|
||||||
else if ( sqmExpression instanceof SqmEnumLiteral<?> ) {
|
if ( sqmExpression instanceof SqmEnumLiteral<?> ) {
|
||||||
final MappingModelExpressible<?> mappingModelExpressible = resolveInferredType();
|
final MappingModelExpressible<?> mappingModelExpressible = resolveInferredType();
|
||||||
if ( mappingModelExpressible != null ) {
|
if ( mappingModelExpressible != null ) {
|
||||||
return mappingModelExpressible;
|
return mappingModelExpressible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( sqmExpression instanceof SqmSubQuery<?> ) {
|
|
||||||
|
if ( sqmExpression instanceof SqmSubQuery<?> ) {
|
||||||
final SqmSubQuery<?> subQuery = (SqmSubQuery<?>) sqmExpression;
|
final SqmSubQuery<?> subQuery = (SqmSubQuery<?>) sqmExpression;
|
||||||
final SqmSelectClause selectClause = subQuery.getQuerySpec().getSelectClause();
|
final SqmSelectClause selectClause = subQuery.getQuerySpec().getSelectClause();
|
||||||
if ( selectClause.getSelections().size() == 1 ) {
|
if ( selectClause.getSelections().size() == 1 ) {
|
||||||
|
@ -5293,9 +5291,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
final SqmExpressible<?> selectionNodeType = subQuerySelection.getNodeType();
|
final SqmExpressible<?> selectionNodeType = subQuerySelection.getNodeType();
|
||||||
if ( selectionNodeType != null ) {
|
if ( selectionNodeType != null ) {
|
||||||
final MappingMetamodel domainModel = creationContext.getSessionFactory()
|
|
||||||
.getRuntimeMetamodels()
|
|
||||||
.getMappingMetamodel();
|
|
||||||
final MappingModelExpressible<?> expressible = domainModel.resolveMappingExpressible(selectionNodeType, this::findTableGroupByPath );
|
final MappingModelExpressible<?> expressible = domainModel.resolveMappingExpressible(selectionNodeType, this::findTableGroupByPath );
|
||||||
|
|
||||||
if ( expressible != null ) {
|
if ( expressible != null ) {
|
||||||
|
@ -5321,6 +5316,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
// We can't determine the type of the expression
|
// We can't determine the type of the expression
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( nodeType instanceof EmbeddedSqmPathSource<?> ) {
|
if ( nodeType instanceof EmbeddedSqmPathSource<?> ) {
|
||||||
if ( sqmExpression instanceof SqmBinaryArithmetic<?> ) {
|
if ( sqmExpression instanceof SqmBinaryArithmetic<?> ) {
|
||||||
final SqmBinaryArithmetic<?> binaryArithmetic = (SqmBinaryArithmetic<?>) sqmExpression;
|
final SqmBinaryArithmetic<?> binaryArithmetic = (SqmBinaryArithmetic<?>) sqmExpression;
|
||||||
|
@ -5332,9 +5328,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final MappingMetamodel domainModel = creationContext.getSessionFactory()
|
|
||||||
.getRuntimeMetamodels()
|
|
||||||
.getMappingMetamodel();
|
|
||||||
final MappingModelExpressible<?> valueMapping = domainModel.resolveMappingExpressible(
|
final MappingModelExpressible<?> valueMapping = domainModel.resolveMappingExpressible(
|
||||||
nodeType,
|
nodeType,
|
||||||
fromClauseIndex::getTableGroup
|
fromClauseIndex::getTableGroup
|
||||||
|
@ -5348,7 +5343,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( valueMapping == null ) {
|
if ( valueMapping == null ) {
|
||||||
// For literals it is totally possible that we can't figure out a mapping type
|
// For literals, it is totally possible that we can't figure out a mapping type
|
||||||
if ( sqmExpression instanceof SqmLiteral<?> ) {
|
if ( sqmExpression instanceof SqmLiteral<?> ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -6785,10 +6780,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
finally {
|
finally {
|
||||||
inferrableTypeAccessStack.pop();
|
inferrableTypeAccessStack.pop();
|
||||||
}
|
}
|
||||||
ComparisonOperator sqmOperator = predicate.getSqmOperator();
|
|
||||||
if ( predicate.isNegated() ) {
|
final ComparisonOperator sqmOperator = predicate.isNegated()
|
||||||
sqmOperator = sqmOperator.negated();
|
? predicate.getSqmOperator().negated()
|
||||||
}
|
: predicate.getSqmOperator();
|
||||||
return new ComparisonPredicate( lhs, sqmOperator, rhs, getBooleanType() );
|
return new ComparisonPredicate( lhs, sqmOperator, rhs, getBooleanType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7099,20 +7094,21 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
@Override
|
@Override
|
||||||
public Object visitBooleanExpressionPredicate(SqmBooleanExpressionPredicate predicate) {
|
public Object visitBooleanExpressionPredicate(SqmBooleanExpressionPredicate predicate) {
|
||||||
final Expression booleanExpression = (Expression) predicate.getBooleanExpression().accept( this );
|
final Expression booleanExpression = (Expression) predicate.getBooleanExpression().accept( this );
|
||||||
if ( booleanExpression instanceof SelfRenderingExpression ) {
|
final JdbcMapping jdbcMapping = booleanExpression.getExpressionType().getJdbcMapping( 0 );
|
||||||
final Predicate sqlPredicate = new SelfRenderingPredicate( (SelfRenderingExpression) booleanExpression );
|
if ( jdbcMapping.getValueConverter() != null ) {
|
||||||
if ( predicate.isNegated() ) {
|
// handle converted booleans (yes-no, etc)
|
||||||
return new NegatedPredicate( sqlPredicate );
|
return new ComparisonPredicate(
|
||||||
}
|
|
||||||
return sqlPredicate;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new BooleanExpressionPredicate(
|
|
||||||
booleanExpression,
|
booleanExpression,
|
||||||
predicate.isNegated(),
|
ComparisonOperator.EQUAL,
|
||||||
getBooleanType()
|
new JdbcLiteral<>( jdbcMapping.convertToRelationalValue( !predicate.isNegated() ), jdbcMapping )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new BooleanExpressionPredicate(
|
||||||
|
booleanExpression,
|
||||||
|
predicate.isNegated(),
|
||||||
|
getBooleanType()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.query.sqm.tree.predicate;
|
package org.hibernate.query.sqm.tree.predicate;
|
||||||
|
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
|
import org.hibernate.query.sqm.SqmExpressible;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -19,7 +20,11 @@ public abstract class AbstractNegatableSqmPredicate extends AbstractSqmPredicate
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractNegatableSqmPredicate(boolean negated, NodeBuilder nodeBuilder) {
|
public AbstractNegatableSqmPredicate(boolean negated, NodeBuilder nodeBuilder) {
|
||||||
super( nodeBuilder.getBooleanType(), nodeBuilder );
|
this( nodeBuilder.getBooleanType(), negated, nodeBuilder );
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractNegatableSqmPredicate(SqmExpressible<Boolean> type, boolean negated, NodeBuilder nodeBuilder) {
|
||||||
|
super( type, nodeBuilder );
|
||||||
this.negated = negated;
|
this.negated = negated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import jakarta.persistence.criteria.Expression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an expression whose type is boolean, and can therefore be used as a predicate.
|
* Represents an expression whose type is boolean, and can therefore be used as a predicate.
|
||||||
|
* E.g. {@code `from Employee e where e.isActive`}
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +35,7 @@ public class SqmBooleanExpressionPredicate extends AbstractNegatableSqmPredicate
|
||||||
SqmExpression<Boolean> booleanExpression,
|
SqmExpression<Boolean> booleanExpression,
|
||||||
boolean negated,
|
boolean negated,
|
||||||
NodeBuilder nodeBuilder) {
|
NodeBuilder nodeBuilder) {
|
||||||
super( negated, nodeBuilder );
|
super( booleanExpression.getExpressible(), negated, nodeBuilder );
|
||||||
|
|
||||||
assert booleanExpression.getNodeType() != null;
|
assert booleanExpression.getNodeType() != null;
|
||||||
final Class<?> expressionJavaType = booleanExpression.getNodeType().getExpressibleJavaType().getJavaTypeClass();
|
final Class<?> expressionJavaType = booleanExpression.getNodeType().getExpressibleJavaType().getJavaTypeClass();
|
||||||
|
@ -86,4 +87,14 @@ public class SqmBooleanExpressionPredicate extends AbstractNegatableSqmPredicate
|
||||||
protected SqmNegatablePredicate createNegatedNode() {
|
protected SqmNegatablePredicate createNegatedNode() {
|
||||||
return new SqmBooleanExpressionPredicate( booleanExpression, !isNegated(), nodeBuilder() );
|
return new SqmBooleanExpressionPredicate( booleanExpression, !isNegated(), nodeBuilder() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if ( isNegated() ) {
|
||||||
|
return "SqmBooleanExpressionPredicate( (not) " + booleanExpression + " )";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "SqmBooleanExpressionPredicate( " + booleanExpression + " )";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue