diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index 52298b7f15..6e9ae8194a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -6245,6 +6245,7 @@ public abstract class BaseSqmToSqlAstConverter 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 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 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 extends Base ); } finally { + inferrableTypeAccessStack.pop(); if ( operator == SUBTRACT ) { negativeAdjustment = !negativeAdjustment; } @@ -6342,15 +6347,19 @@ public abstract class BaseSqmToSqlAstConverter 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 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 diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java index 29fba74b61..e57bc1c38b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java @@ -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(