HHH-17074 Type inference in duration arithmetic is wrong

This commit is contained in:
Christian Beikov 2023-08-14 18:32:57 +02:00
parent 10baf4398a
commit 6a56fc62e5
2 changed files with 33 additions and 2 deletions

View File

@ -6245,6 +6245,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final BinaryArithmeticOperator operator = expression.getOperator();
final SqmExpression<?> lhs = SqmExpressionHelper.getActualExpression( expression.getLeftHandOperand() );
final SqmExpression<?> rhs = SqmExpressionHelper.getActualExpression( expression.getRightHandOperand() );
final FromClauseIndex fromClauseIndex = fromClauseIndexStack.getCurrent();
// we have a date or timestamp somewhere to
// the right of us, so we need to restructure
@ -6277,7 +6278,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
Expression timestamp = adjustedTimestamp;
SqmExpressible<?> timestampType = adjustedTimestampType;
inferrableTypeAccessStack.push( () -> determineValueMapping( rhs, fromClauseIndex ) );
adjustedTimestamp = toSqlExpression( lhs.accept( this ) );
inferrableTypeAccessStack.pop();
JdbcMappingContainer type = adjustedTimestamp.getExpressionType();
if ( type instanceof SqmExpressible) {
adjustedTimestampType = (SqmExpressible<?>) type;
@ -6293,6 +6296,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
negativeAdjustment = !negativeAdjustment;
}
try {
inferrableTypeAccessStack.push( () -> determineValueMapping( lhs, fromClauseIndex ) );
final Object result = rhs.accept( this );
if ( result instanceof SqlTupleContainer ) {
return result;
@ -6324,6 +6328,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
}
finally {
inferrableTypeAccessStack.pop();
if ( operator == SUBTRACT ) {
negativeAdjustment = !negativeAdjustment;
}
@ -6342,15 +6347,19 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// x * (d1 - d2) => x * d1 - x * d2
// -x * (d1 + d2) => - x * d1 - x * d2
// -x * (d1 - d2) => - x * d1 + x * d2
inferrableTypeAccessStack.push( () -> determineValueMapping( rhs, fromClauseIndex ) );
Expression duration = toSqlExpression( lhs.accept( this ) );
inferrableTypeAccessStack.pop();
Expression scale = adjustmentScale;
boolean negate = negativeAdjustment;
adjustmentScale = applyScale( duration );
negativeAdjustment = false; //was sucked into the scale
try {
inferrableTypeAccessStack.push( () -> determineValueMapping( lhs, fromClauseIndex ) );
return rhs.accept( this );
}
finally {
inferrableTypeAccessStack.pop();
adjustmentScale = scale;
negativeAdjustment = negate;
}
@ -6379,8 +6388,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final SqmExpression<?> lhs = SqmExpressionHelper.getActualExpression( expression.getLeftHandOperand() );
final SqmExpression<?> rhs = SqmExpressionHelper.getActualExpression( expression.getRightHandOperand() );
Expression left = getActualExpression( cleanly( () -> toSqlExpression( lhs.accept( this ) ) ) );
Expression right = getActualExpression( cleanly( () -> toSqlExpression( rhs.accept( this ) ) ) );
final FromClauseIndex fromClauseIndex = fromClauseIndexStack.getCurrent();
inferrableTypeAccessStack.push( () -> determineValueMapping( rhs, fromClauseIndex ) );
final Expression left = getActualExpression( cleanly( () -> toSqlExpression( lhs.accept( this ) ) ) );
inferrableTypeAccessStack.pop();
inferrableTypeAccessStack.push( () -> determineValueMapping( lhs, fromClauseIndex ) );
final Expression right = getActualExpression( cleanly( () -> toSqlExpression( rhs.accept( this ) ) ) );
inferrableTypeAccessStack.pop();
// The result of timestamp subtraction is always a `Duration`, unless a unit is applied
// So use SECOND granularity with fractions as that is what the `DurationJavaType` expects

View File

@ -25,6 +25,7 @@ import org.hibernate.testing.orm.domain.gambit.EntityOfMaps;
import org.hibernate.testing.orm.domain.gambit.SimpleEntity;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -1406,6 +1407,22 @@ public class FunctionTests {
);
}
@Test
@JiraKey("HHH-17074")
public void testDurationArithmeticWithParameters(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
assertEquals(
1,
session.createQuery( "from EntityOfBasics e where (:date - e.theTimestamp) by day > 1" )
.setParameter( "date", Timestamp.valueOf( "2022-01-01 00:00:00" ) )
.getResultList()
.size()
);
}
);
}
@Test
public void testIntervalDiffExpressions(SessionFactoryScope scope) {
scope.inTransaction(