Fix type inference for case expressions and simple case SQL rendering issue

This commit is contained in:
Christian Beikov 2020-01-29 18:18:22 +01:00 committed by Steve Ebersole
parent f66728d5b2
commit 1cd5ea61f6
5 changed files with 78 additions and 21 deletions

View File

@ -47,6 +47,7 @@ import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
@ -697,6 +698,10 @@ public class MappingMetamodelImpl implements MappingMetamodel, MetamodelImplemen
return (BasicType) sqmExpressable;
}
if ( sqmExpressable instanceof BasicSqmPathSource<?> ) {
return getTypeConfiguration().getBasicTypeForJavaType(((BasicSqmPathSource<?>) sqmExpressable).getJavaType());
}
if ( sqmExpressable instanceof CompositeSqmPathSource ) {
throw new NotYetImplementedFor6Exception( "Resolution of embedded-valued SqmExpressable nodes not yet implemented" );
}

View File

@ -31,6 +31,7 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.BinaryArithmeticOperator;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.UnaryArithmeticOperator;
import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
@ -838,6 +839,23 @@ public abstract class BaseSqmToSqlAstConverter
);
}
protected MappingModelExpressable<?> resolveMappingExpressable(SqmExpressable<?> nodeType) {
final MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
if ( valueMapping == null ) {
final Supplier<MappingModelExpressable> currentExpressableSupplier = inferableTypeAccessStack.getCurrent();
if ( currentExpressableSupplier != null ) {
return currentExpressableSupplier.get();
}
}
if ( valueMapping == null ) {
throw new ConversionException( "Could not determine ValueMapping for SqmExpressable: " + nodeType );
}
return valueMapping;
}
protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmExpression) {
if ( sqmExpression instanceof SqmParameter ) {
return determineValueMapping( (SqmParameter) sqmExpression );
@ -871,7 +889,6 @@ public abstract class BaseSqmToSqlAstConverter
return valueMapping;
}
@SuppressWarnings("WeakerAccess")
protected MappingModelExpressable<?> determineValueMapping(SqmParameter<?> sqmParameter) {
log.debugf( "Determining mapping-model type for SqmParameter : %s", sqmParameter );
@ -1486,37 +1503,59 @@ public abstract class BaseSqmToSqlAstConverter
@Override
public CaseSimpleExpression visitSimpleCaseExpression(SqmCaseSimple<?,?> expression) {
final CaseSimpleExpression result = new CaseSimpleExpression(
determineValueMapping( expression ),
(Expression) expression.getFixture().accept( this )
);
for ( SqmCaseSimple.WhenFragment whenFragment : expression.getWhenFragments() ) {
result.when(
(Expression) whenFragment.getCheckValue().accept( this ),
(Expression) whenFragment.getResult().accept( this )
SqmExpressable<?> resultType = expression.getNodeType();
List<CaseSimpleExpression.WhenFragment> whenFragments = new ArrayList<>( expression.getWhenFragments().size() );
for ( SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments() ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, whenFragment.getResult().getNodeType() );
whenFragments.add(
new CaseSimpleExpression.WhenFragment(
(Expression) whenFragment.getCheckValue().accept(this),
(Expression) whenFragment.getResult().accept(this)
)
);
}
result.otherwise( (Expression) expression.getOtherwise().accept( this ) );
Expression otherwise = null;
if ( expression.getOtherwise() != null ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, expression.getOtherwise().getNodeType() );
otherwise = (Expression) expression.getOtherwise().accept(this );
}
final CaseSimpleExpression result = new CaseSimpleExpression(
resolveMappingExpressable( resultType ),
(Expression) expression.getFixture().accept( this ),
whenFragments,
otherwise
);
return result;
}
@Override
public CaseSearchedExpression visitSearchedCaseExpression(SqmCaseSearched<?> expression) {
final CaseSearchedExpression result = new CaseSearchedExpression(
determineValueMapping( expression )
);
for ( SqmCaseSearched.WhenFragment whenFragment : expression.getWhenFragments() ) {
result.when(
(Predicate) whenFragment.getPredicate().accept( this ),
(Expression) whenFragment.getResult().accept( this )
SqmExpressable<?> resultType = expression.getNodeType();
List<CaseSearchedExpression.WhenFragment> whenFragments = new ArrayList<>( expression.getWhenFragments().size() );
for ( SqmCaseSearched.WhenFragment<?> whenFragment : expression.getWhenFragments() ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, whenFragment.getResult().getNodeType() );
whenFragments.add(
new CaseSearchedExpression.WhenFragment(
(Predicate) whenFragment.getPredicate().accept(this),
(Expression) whenFragment.getResult().accept(this)
)
);
}
result.otherwise( (Expression) expression.getOtherwise().accept( this ) );
Expression otherwise = null;
if ( expression.getOtherwise() != null ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, expression.getOtherwise().getNodeType() );
otherwise = (Expression) expression.getOtherwise().accept(this );
}
final CaseSearchedExpression result = new CaseSearchedExpression(
resolveMappingExpressable( resultType ),
whenFragments,
otherwise
);
return result;
}

View File

@ -818,7 +818,7 @@ public abstract class AbstractSqlAstWalker
@Override
public void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression) {
appendSql( " case" );
appendSql( "case " );
caseSimpleExpression.getFixture().accept( this );
for ( CaseSimpleExpression.WhenFragment whenFragment : caseSimpleExpression.getWhenFragments() ) {
appendSql( " when " );

View File

@ -36,6 +36,12 @@ public class CaseSearchedExpression implements Expression, DomainResultProducer
this.type = (BasicType) type;
}
public CaseSearchedExpression(MappingModelExpressable type, List<WhenFragment> whenFragments, Expression otherwise) {
this.type = (BasicType) type;
this.whenFragments = whenFragments;
this.otherwise = otherwise;
}
public List<WhenFragment> getWhenFragments() {
return whenFragments;
}

View File

@ -32,6 +32,13 @@ public class CaseSimpleExpression implements Expression, DomainResultProducer {
this.fixture = fixture;
}
public CaseSimpleExpression(MappingModelExpressable type, Expression fixture, List<WhenFragment> whenFragments, Expression otherwise) {
this.type = type;
this.fixture = fixture;
this.whenFragments = whenFragments;
this.otherwise = otherwise;
}
public Expression getFixture() {
return fixture;
}