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 96247c0e33
commit 4fb57f9a15
2 changed files with 33 additions and 2 deletions

View File

@ -6277,6 +6277,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
@ -6309,7 +6310,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;
@ -6325,6 +6328,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;
@ -6356,6 +6360,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
}
finally {
inferrableTypeAccessStack.pop();
if ( operator == SUBTRACT ) {
negativeAdjustment = !negativeAdjustment;
}
@ -6374,15 +6379,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;
}
@ -6411,8 +6420,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

@ -24,6 +24,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;
@ -1588,6 +1589,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(