Skip to content

Passing null as stored procedure argument is broken in v2.7.0 (works in v2.6.8). #2544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
denis111 opened this issue May 23, 2022 · 22 comments
Closed
Assignees
Labels
type: regression A regression from a previous release

Comments

@denis111
Copy link

denis111 commented May 23, 2022

With spring.jpa.properties.hibernate.proc.param_null_passing=true we can pass null as stored procedure as parameter without any problem with Spring Boot 2.6.8 but upgrading to v2.7.0 throws exception with the same Hibernate version. I've tried only with PostgreSQL and UUID as procedure parameter but I suppose it could be for any type of DB and parameters. The exception is:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Bind value [org.hibernate.jpa.TypedParameterValue@5b1420f9] was not of specified type [class java.util.UUID; nested exception is java.lang.IllegalArgumentException: Bind value [org.hibernate.jpa.TypedParameterValue@5b1420f9] was not of specified type [class java.util.UUID

Example:

public interface TestModelRepository extends JpaRepository<TestModel, Long> {
  @Procedure("countByUuid")
  void countUuid(UUID one);
}

then just call testModelRepository.countUuid(null).
I've prepared a sample project to reproduce the problem, just change Spring Boot version to 2.6.8 and it works fine: https://github.com/denis111/spring-data-jpa270test

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 23, 2022
gregturn added a commit that referenced this issue Jul 13, 2022
Properly handle null values with like or contains.

Null values are wrapped with a special handler when interacting with Hibernate. However, this becomes an issue for queries when LIKE or CONTAINS are applied. In this situation, the null needs to be condensed into an empty string and any wildcards can then be applied with expected results.

Closes #2548, #2570.
Supercedes: #2585.
Related: #2461, #2544#
gregturn added a commit that referenced this issue Jul 13, 2022
Null values are wrapped with a special handler when interacting with Hibernate. However, this becomes an issue for queries when LIKE or CONTAINS are applied. In this situation, the null needs to be condensed into an empty string and any wildcards can then be applied with expected results.

Closes #2548, #2570.
Supercedes: #2585.
Related: #2461, #2544#
gregturn added a commit that referenced this issue Jul 13, 2022
Null values are wrapped with a special handler when interacting with Hibernate. However, this becomes an issue for queries when LIKE or CONTAINS are applied. In this situation, the null needs to be condensed into an empty string and any wildcards can then be applied with expected results.

Closes #2548, #2570.
Supercedes: #2585.
Related: #2461, #2544#
gregturn added a commit that referenced this issue Jul 13, 2022
Null values are wrapped with a special handler when interacting with Hibernate. However, this becomes an issue for queries when LIKE or CONTAINS are applied. In this situation, the null needs to be condensed into an empty string and any wildcards can then be applied with expected results.

Closes #2548, #2570.
Supercedes: #2585.
Related: #2461, #2544#
@gregturn
Copy link
Contributor

gregturn commented Jul 14, 2022

I ran your code against Spring Boot 3.0.0-M3 and it failed the same. I also ran it against Spring Boot 3.0.0-SNAPSHOT and it worked. I'd like to pinpoint the patch so I can assess whether it's a candidate for backporting.

Can also confirm the issue still resides in Spring Boot 2.7.2-SNAPSHOT, so a patch that wasn't backported.

@SchlauFuchs
Copy link

SchlauFuchs commented Jul 29, 2022

This might explain our current issue using an @Procedure annotation with a number of parameters where one is nullable, and we suddenly get a Bind value issue. Using V2.7.2

@stylepatrick
Copy link

stylepatrick commented Aug 16, 2022

The same problem occurs with Oracle database. Calling a procedure with a nullable parameter leads to the following error:

java.lang.IllegalArgumentException: Bind value [org.hibernate.jpa.TypedParameterValue@42dae24d] was not of specified type [class java.lang.String

It works with all versions < 2.6.10.

Is a correction planned or are nullable parameters no longer supported?

@SchlauFuchs
Copy link

is this still broken with 2.7.3? we downgraded to 2.6.8, waiting for the fix.

@quaff
Copy link
Contributor

quaff commented Sep 14, 2022

is this still broken with 2.7.3? we downgraded to 2.6.8, waiting for the fix.

It should fixed in 2.7.3, but it's not released yet. @gregturn

@apatel0708
Copy link

we are using 2.7.3 and this is still an issue. did you mean it will be fixed in 2.7.4?

@denis111
Copy link
Author

I've just tried 2.7.4 and the issue is still there, I have updated my test project.

gregturn added a commit that referenced this issue Sep 23, 2022
Null values are wrapped with a special handler when interacting with Hibernate. However, this becomes an issue for queries when LIKE or CONTAINS are applied. In this situation, the null needs to be condensed into an empty string and any wildcards can then be applied with expected results.

Closes #2548, #2570.
Supercedes: #2585.
Related: #2461, #2544#
@denis111
Copy link
Author

v2.7.5, the issue is still there, updated my test project.

@quaff
Copy link
Contributor

quaff commented Oct 21, 2022

@denis111 It should be fixed at hibernate side, I have created hibernate/hibernate-orm#5438

gregturn added a commit that referenced this issue Nov 7, 2022
gregturn added a commit that referenced this issue Nov 9, 2022
gregturn added a commit that referenced this issue Nov 9, 2022
@kashann
Copy link

kashann commented Nov 25, 2022

Any idea when will the issue be fixed?

@denis111
Copy link
Author

The issue is still present un v2.7.6 but it's solved in v3.0.0. I've updated my test project and created the branch spring-boot-3.

@gregturn
Copy link
Contributor

The issue was clearly mended when Spring Data JPA moved to Hibernate 6 in Spring Boot 3.0.0-M4 (Spring Data 2022.0.0-M5).

You can see ALL the changes that happened in Spring Data JPA between 3.0.0-M4 and 3.0.0-M5, and nothing stands out except upgrading to Hibernate 6 and properly handling nulls for LIKEs. The former will never be backported to 2.7.x and the latter already has been in 2.7.6.

@SchlauFuchs
Copy link

SchlauFuchs commented Dec 16, 2022 via email

@gregturn
Copy link
Contributor

I have created a test case inside Spring Data JPA 2.7.x that replicates the error message first reported at the top. I want to isolate if this is specific to UUID or is something else.

@gregturn
Copy link
Contributor

Okay, changing the reproducer's type to uuid to varchar/String results in a slightly different error. But it has the same pattern.

gregturn added a commit that referenced this issue Dec 19, 2022
@gregturn
Copy link
Contributor

Looks like our TypedParameterValue solution to support Hibernate is the culprit here. If I look for that type when setting stored procedure parameters, and dereference it, it works. I believe that was introduced in 2.7, which would explain why it still works in 2.6.

@gregturn
Copy link
Contributor

gregturn commented Dec 19, 2022

Thanks @quaff for submitting the PR (#2544 (comment)). Until they accept that PR, I can conditionally de-reference the TypedParameterValue on our end for stored procedure calls.

gregturn added a commit that referenced this issue Dec 19, 2022
Hibernate supports TypedParameterValue in queries, but not stored procedures.

Until hibernate/hibernate-orm#5438 is adopted, we have to dereference such parameters on our end first.

Closes #2544.
gregturn added a commit that referenced this issue Dec 19, 2022
Hibernate supports TypedParameterValue in queries, but not stored procedures.

Until hibernate/hibernate-orm#5438 is adopted, we have to dereference such parameters on our end first.

Closes #2544.
@gregturn gregturn added type: regression A regression from a previous release and removed status: waiting-for-triage An issue we've not yet triaged labels Dec 19, 2022
@gregturn gregturn added this to the 2.7.7 (2021.2.7) milestone Dec 19, 2022
gregturn added a commit that referenced this issue Dec 19, 2022
Hibernate supports TypedParameterValue in queries, but not stored procedures.

Until hibernate/hibernate-orm#5438 is adopted, we have to dereference such parameters on our end first.

Closes #2544.
@gregturn
Copy link
Contributor

Issue resolved. Check it out in 2.7.7-SNAPSHOT.

gregturn added a commit that referenced this issue Dec 19, 2022
Hibernate 6.1 properly handles TypeParameterValue for general parameters, but not for temporal ones. So we must dereference in those scenarios.

Related: #2544, hibernate/hibernate-orm#5438
gregturn added a commit that referenced this issue Dec 19, 2022
Hibernate 6.1 properly handles TypeParameterValue for general parameters, but not for temporal ones. So we must dereference in those scenarios.

Related: #2544, hibernate/hibernate-orm#5438
gregturn added a commit that referenced this issue Dec 19, 2022
Hibernate 6.1 properly handles TypeParameterValue for general parameters, but not for temporal ones. So we must dereference in those scenarios.

Related: #2544, hibernate/hibernate-orm#5438
@gregturn
Copy link
Contributor

Merged forward to 3.0.x and main.

While TypedParameterValue is handled properly in Hibernate 6.1 for general parameter types, it still requires dereferencing for temporal types.

CC @quaff

@denis111
Copy link
Author

@gregturn it looks like it didn't get to Spring Boot 2.7.7 (I've updated my test project), should we wait for 2.7.8 or it will never be included in 2.7.x branch?

@SchlauFuchs
Copy link

SchlauFuchs commented Jan 20, 2023

@gregturn We still have this issue. Here a stack trace:

org.springframework.dao.InvalidDataAccessApiUsageException: Bind value [org.hibernate.jpa.TypedParameterValue@2cff35e7] was not of specified type [class java.lang.String; nested exception is java.lang.IllegalArgumentException: Bind value [org.hibernate.jpa.TypedParameterValue@2cff35e7] was not of specified type [class java.lang.String
	at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374)
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235)
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
	at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
	at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:145)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:99)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at jdk.proxy3/jdk.proxy3.$Proxy279.assignJob(Unknown Source)
...
     Caused by: java.lang.IllegalArgumentException: Bind value [org.hibernate.jpa.TypedParameterValue@2cff35e7] was not of specified type [class java.lang.String
     	at org.hibernate.procedure.internal.ParameterBindImpl.internalSetValue(ParameterBindImpl.java:94)
     	at org.hibernate.procedure.internal.ParameterBindImpl.setBindValue(ParameterBindImpl.java:64)
     	at org.hibernate.procedure.internal.ProcedureCallImpl.setParameter(ProcedureCallImpl.java:817)
     	at org.hibernate.procedure.internal.ProcedureCallImpl.setParameter(ProcedureCallImpl.java:70)
     	at org.springframework.data.jpa.repository.query.QueryParameterSetter$BindableQuery.setParameter(QueryParameterSetter.java:326)
     	at org.springframework.data.jpa.repository.query.QueryParameterSetter$NamedOrIndexedQueryParameterSetter.lambda$setParameter$4(QueryParameterSetter.java:117)
     	at org.springframework.data.jpa.repository.query.QueryParameterSetter$ErrorHandling$1.execute(QueryParameterSetter.java:140)
     	at org.springframework.data.jpa.repository.query.QueryParameterSetter$NamedOrIndexedQueryParameterSetter.setParameter(QueryParameterSetter.java:117)
     	at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:82)
     	at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:74)
     	at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.doCreateQuery(StoredProcedureJpaQuery.java:102)
     	at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.createQuery(StoredProcedureJpaQuery.java:89)
     	at org.springframework.data.jpa.repository.query.JpaQueryExecution$ProcedureExecution.doExecute(JpaQueryExecution.java:318)
     	at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:90)
     	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:156)
     	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:144)
     	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
     	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
     	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:160)
     	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:139)
     	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
     	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:81)
     	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
     	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
     	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
     	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
     	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
     	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)

@SchlauFuchs
Copy link

Seems like there is a dependency mismatch. Using springboot-starter-data-jpa 2.7.8 it works, and it has the transient dependency to spring-data-jpa 2.7.7.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

No branches or pull requests

8 participants