From 8b1fafa106c05d47f28ed30df1e9499178b47efe Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 11 Sep 2024 15:37:31 +0200 Subject: [PATCH 1/2] HHH-18556 Add test for issue --- .../query/SelectCaseWhenNullLiteralTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SelectCaseWhenNullLiteralTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SelectCaseWhenNullLiteralTest.java index 836e7df34a6e..330e804078c2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SelectCaseWhenNullLiteralTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SelectCaseWhenNullLiteralTest.java @@ -4,6 +4,7 @@ import org.hibernate.testing.TestForIssue; import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.junit.jupiter.api.AfterEach; @@ -55,6 +56,30 @@ public void testSelectCaseWhenNullLiteral(SessionFactoryScope scope) { ); } + @Test + @JiraKey( "HHH-18556" ) + public void testSelectCaseWhenNullLiteralWithParameters(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List result = session.createQuery( "select case when 1=1 then ?1 else null end from Person p" ) + .setParameter( 1, 2 ) + .list(); + assertThat( result.size(), is( 1 ) ); + assertThat( result.get( 0 ), is( 2 ) ); + } + ); + + scope.inTransaction( + session -> { + List result = session.createQuery( "select count(case when 1=1 then ?1 else null end) from Person p" ) + .setParameter( 1, 2 ) + .list(); + assertThat( result.size(), is( 1 ) ); + assertThat( result.get( 0 ), is( 1L ) ); + } + ); + } + @Entity(name = "Person") @Table(name = "PERSON_TABLE") public static class Person { From 46f8691cd63eb374b06a4841381225a25dbbe684 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 11 Sep 2024 15:44:25 +0200 Subject: [PATCH 2/2] HHH-18556 Expressions.nullExpresion() in querydsl result in NPE in SqmExpressible --- .../internal/QueryParameterBindingImpl.java | 28 ++++++++++++------- .../spi/AbstractCommonQueryContract.java | 3 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java index e5ea76cb30c8..5f102201ae5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java @@ -20,6 +20,7 @@ import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindingValidator; import org.hibernate.query.sqm.SqmExpressible; +import org.hibernate.query.sqm.tree.expression.NullSqmExpressible; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaTypeHelper; import org.hibernate.type.spi.TypeConfiguration; @@ -113,10 +114,10 @@ public void setBindValue(T value, boolean resolveJdbcTypeIfNecessary) { final Object coerced; if ( ! sessionFactory.getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled() ) { try { - if ( bindType != null ) { + if ( canValueBeCoerced( bindType) ) { coerced = coerce( value, bindType ); } - else if ( queryParameter.getHibernateType() != null ) { + else if ( canValueBeCoerced( queryParameter.getHibernateType() ) ) { coerced = coerce( value, queryParameter.getHibernateType() ); } else { @@ -190,7 +191,7 @@ private boolean isRegisteredAsBasicType(Class valueClass) { private void bindValue(Object value) { isBound = true; bindValue = value; - if ( bindType == null && value != null ) { + if ( canBindValueBeSet( value, bindType ) ) { bindType = sessionFactory.getMappingMetamodel().resolveParameterBindType( value ); } } @@ -206,10 +207,10 @@ public void setBindValue(T value, BindableType clarifiedType) { } final Object coerced; - if ( bindType != null ) { + if ( canValueBeCoerced( bindType ) ) { coerced = coerce( value, bindType ); } - else if ( queryParameter.getHibernateType() != null ) { + else if ( canValueBeCoerced( queryParameter.getHibernateType() ) ) { coerced = coerce( value, queryParameter.getHibernateType() ); } else { @@ -233,7 +234,7 @@ public void setBindValue(T value, TemporalType temporalTypePrecision) { final Object coerced; if ( ! sessionFactory.getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled() ) { - if ( bindType != null ) { + if (canValueBeCoerced( bindType ) ) { try { coerced = coerce( value, bindType ); } @@ -249,7 +250,7 @@ public void setBindValue(T value, TemporalType temporalTypePrecision) { ); } } - else if ( queryParameter.getHibernateType() != null ) { + else if ( canValueBeCoerced( queryParameter.getHibernateType() ) ) { coerced = coerce( value, queryParameter.getHibernateType() ); } else { @@ -299,10 +300,9 @@ public void setBindValues(Collection values) { value = iterator.next(); } - if ( bindType == null && value != null ) { - this.bindType = sessionFactory.getMappingMetamodel().resolveParameterBindType( value ); + if ( canBindValueBeSet( value, bindType ) ) { + bindType = sessionFactory.getMappingMetamodel().resolveParameterBindType( value ); } - } @Override @@ -378,4 +378,12 @@ private void validate(Object value, TemporalType clarifiedTemporalType) { public TypeConfiguration getTypeConfiguration() { return sessionFactory.getTypeConfiguration(); } + + private static boolean canValueBeCoerced(BindableType bindType) { + return bindType != null && !( bindType instanceof NullSqmExpressible ); + } + + private static boolean canBindValueBeSet(Object value, BindableType bindType) { + return value != null && ( bindType == null || bindType instanceof NullSqmExpressible ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java index 32f8739f9515..173e0204f7d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java @@ -45,6 +45,7 @@ import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.internal.QueryOptionsImpl; import org.hibernate.query.sqm.SqmExpressible; +import org.hibernate.query.sqm.tree.expression.NullSqmExpressible; import org.hibernate.query.sqm.tree.expression.SqmLiteral; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; @@ -906,7 +907,7 @@ public CommonQueryContract setParameter(int position, Object value) { final QueryParameter param = binding.getQueryParameter(); if ( param.allowsMultiValuedBinding() ) { final BindableType hibernateType = param.getHibernateType(); - if ( hibernateType == null || isInstance( hibernateType, value ) ) { + if ( hibernateType == null || hibernateType instanceof NullSqmExpressible || isInstance( hibernateType, value ) ) { if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) { //noinspection rawtypes return setParameterList( position, (Collection) value );