Skip to content
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

Query methods with tuple bind parameter List<String[]> does no longer work #1323

Closed
fmisir opened this issue Sep 5, 2022 · 6 comments
Closed
Assignees
Labels
type: regression A regression from a previous release

Comments

@fmisir
Copy link

fmisir commented Sep 5, 2022

The following query doesn't work any more with spring-data-jdbc versions 2.4.1 & 2.4.2. It works in version 2.4.0.

@Query(
        "select distinct s.id_external from shell s where s.id in (" +
                "select si.fk_shell_id from shell_identifier si " +
                "join (values :keyValueCombinations ) as t (input_key,input_value) " +
                "ON si.namespace = input_key " +
                    "AND si.identifier = input_value " +
                "group by si.fk_shell_id " +
                ")"
)
List<String> findExternalShellIdsByIdentifiers(@Param("keyValueCombinations") List<String[]> keyValueCombinations);

The invocation of the method is like this:

List<String[]> keyValueCombinations = List.of(new String[]{"key1", "value1"}, new String[]{"key2", "value2"});
findExternalShellIdsByIdentifiers(keyValueCombinations)

I tested it with PostgreSQL and H2.

PostgreSQL
Version: postgres:13.6-alpine
Driver-Version: 42.5.0
Error:

org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select s.id_external from shell s where s.id in (select si.fk_shell_id from shell_identifier si join (values ?, ?, ? ) as t (input_key,input_value) ON si.namespace = input_key AND si.identifier = input_value group by si.fk_shell_id having  )]; nested exception is org.postgresql.util.PSQLException: Cannot cast an instance of java.util.ArrayList to type Types.ARRAY

H2
Version: 2.1.214
Error:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column count does not match; SQL statement:
select s.id_external from shell s where s.id in (select si.fk_shell_id from shell_identifier si join (values ?, ?, ? ) as t (input_key,input_value) ON si.namespace = input_key AND si.identifier = input_value group by si.fk_shell_id ) [21002-214]

The issue seams to be here:
2.4.0...2.4.2#diff-b8453546f8ae7cc224005f536bb3be8a0c341186f2cf38b2b34d958cc769ac4cR171

The if condition should evaluate to false for Iterables containing array objects.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 5, 2022
@schauder
Copy link
Contributor

schauder commented Sep 7, 2022

Please provide a Minimimal Reproducable Example, preferable as a Github repository. Make sure to include the database, either as an in memory database or if that is not possible using Testcontainers.

@schauder schauder added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Sep 7, 2022
@spring-projects-issues
Copy link

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Sep 14, 2022
@fmisir
Copy link
Author

fmisir commented Sep 15, 2022

@schauder here is the Minimal Reproducable Example: https://github.com/bci-oss/spring-data-jdbc-1323
Thanks!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue labels Sep 15, 2022
@loolzaaa loolzaaa mentioned this issue Oct 5, 2022
4 tasks
@schauder schauder self-assigned this Oct 11, 2022
@jipipi
Copy link

jipipi commented Mar 22, 2023

Any update on this issue?

It's still not possible to use spring-data-jdbc query with a "IN" containing tuple (spring-data-jdbc version 2.4.8)

The exemple provided can be simplified with simple IN criteria
@Query(""" select p.lastname from person p WHERE (lastname, firstname) IN (:combinations) """ ) List<String> findLastnameWithTupleIn(@Param("combinations") List<String[]> combinations);

Error with postgresql:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select p.lastname from person p WHERE (lastname, firstname) IN (?, ?) ]; nested exception is org.postgresql.util.PSQLException: Cannot cast an instance of java.util.ArrayList to type Types.ARRAY

Errro with H2:
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [select p.lastname from person p WHERE (lastname, firstname) IN (?, ?) ]; Serialization failed, cause: "java.io.NotSerializableException: org.h2.jdbc.JdbcArray" [90026-214]; nested exception is org.h2.jdbc.JdbcSQLDataException: Serialization failed, cause: "java.io.NotSerializableException: org.h2.jdbc.JdbcArray" [90026-214]

The workaround is to use directly NamedParameterJdbcTemplate :
namedParameterJdbcTemplate.query("select p.lastname from person p WHERE (lastname, firstname) IN (:combinations)", Map.of("combinations", combinations), myRowMapper))
But we need to implement a custom rowMapper and we can't use the auto mapping providing by spring data jdbc. That is painful for complex aggregate.

@kurtn718 kurtn718 self-assigned this Mar 22, 2023
@tunacicek
Copy link

@schauder Is there an update to this issue?
The problem is still there.

Thanks for your feedback

@chamgda
Copy link

chamgda commented Jun 10, 2024

This issue is still present in Spring Data JDBC 2.4.18.

In my case in conjunction with MariaDB:

org.springframework.dao.InvalidDataAccessApiUsageException: ConnectionCallback; (conn=48692) Array type is not supported; nested exception is java.sql.SQLFeatureNotSupportedException: (conn=48692) Array type is not supported
	at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) ~[spring-jdbc-5.3.31.jar:5.3.31]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-5.3.31.jar:5.3.31]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82) ~[spring-jdbc-5.3.31.jar:5.3.31]
	at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1577) ~[spring-jdbc-5.3.31.jar:5.3.31]
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:344) ~[spring-jdbc-5.3.31.jar:5.3.31]
	at org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory.createArray(DefaultJdbcTypeFactory.java:75) ~[spring-data-jdbc-2.4.18.jar:2.4.18]
	at org.springframework.data.jdbc.core.convert.BasicJdbcConverter.writeJdbcValue(BasicJdbcConverter.java:313) ~[spring-data-jdbc-2.4.18.jar:2.4.18]
	at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.convertAndAddParameter(StringBasedJdbcQuery.java:181) ~[spring-data-jdbc-2.4.18.jar:2.4.18]
	at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.bindParameters(StringBasedJdbcQuery.java:155) ~[spring-data-jdbc-2.4.18.jar:2.4.18]
	at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.execute(StringBasedJdbcQuery.java:136) ~[spring-data-jdbc-2.4.18.jar:2.4.18]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.7.18.jar:2.7.18]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.7.18.jar:2.7.18]
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:160) ~[spring-data-commons-2.7.18.jar:2.7.18]
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:139) ~[spring-data-commons-2.7.18.jar:2.7.18]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.31.jar:5.3.31]
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.31.jar:5.3.31]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.31.jar:5.3.31]
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.31.jar:5.3.31]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.31.jar:5.3.31]
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.31.jar:5.3.31]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.31.jar:5.3.31]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.31.jar:5.3.31]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.31.jar:5.3.31]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:241) ~[spring-aop-5.3.31.jar:5.3.31]
	at jdk.proxy4/jdk.proxy4.$Proxy86.findAllLeikaleistungVerfahren(Unknown Source) ~[na:na]
	at de.chamaeleon.didaexporter.service.VerfahrenExportService.exportVerfahren(VerfahrenExportService.java:73) ~[classes/:na]
	at de.chamaeleon.didaexporter.service.DidaExportService.export(DidaExportService.java:67) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:344) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:229) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:166) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:145) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:429) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:386) ~[spring-context-5.3.31.jar:5.3.31]
	at org.springframework.boot.context.event.EventPublishingRunListener.ready(EventPublishingRunListener.java:114) ~[spring-boot-2.7.18.jar:2.7.18]
	at org.springframework.boot.SpringApplicationRunListeners.lambda$ready$6(SpringApplicationRunListeners.java:82) ~[spring-boot-2.7.18.jar:2.7.18]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120) ~[spring-boot-2.7.18.jar:2.7.18]
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114) ~[spring-boot-2.7.18.jar:2.7.18]
	at org.springframework.boot.SpringApplicationRunListeners.ready(SpringApplicationRunListeners.java:82) ~[spring-boot-2.7.18.jar:2.7.18]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) ~[spring-boot-2.7.18.jar:2.7.18]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.7.18.jar:2.7.18]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) ~[spring-boot-2.7.18.jar:2.7.18]
	at de.chamaeleon.didaexporter.DidaExporterApplication.main(DidaExporterApplication.java:10) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-2.7.18.jar:2.7.18]
Caused by: java.sql.SQLFeatureNotSupportedException: (conn=48692) Array type is not supported
	at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:281) ~[mariadb-java-client-3.4.0.jar:na]
	at org.mariadb.jdbc.export.ExceptionFactory.notSupported(ExceptionFactory.java:333) ~[mariadb-java-client-3.4.0.jar:na]
	at org.mariadb.jdbc.Connection.createArrayOf(Connection.java:743) ~[mariadb-java-client-3.4.0.jar:na]
	at com.zaxxer.hikari.pool.HikariProxyConnection.createArrayOf(HikariProxyConnection.java) ~[HikariCP-4.0.3.jar:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.jdbc.core.JdbcTemplate$CloseSuppressingInvocationHandler.invoke(JdbcTemplate.java:1650) ~[spring-jdbc-5.3.31.jar:5.3.31]
	at jdk.proxy2/jdk.proxy2.$Proxy52.createArrayOf(Unknown Source) ~[na:na]
	at org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory.lambda$createArray$1(DefaultJdbcTypeFactory.java:75) ~[spring-data-jdbc-2.4.18.jar:2.4.18]
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:336) ~[spring-jdbc-5.3.31.jar:5.3.31]
	... 49 common frames omitted

@schauder schauder added the type: bug A general bug label Jun 18, 2024
@schauder schauder removed the status: feedback-provided Feedback has been provided label Jul 17, 2024
schauder added a commit that referenced this issue Jul 18, 2024
@mp911de mp911de changed the title Query with bind parameter of type List<String[]> does no longer work with versions 2.4.1 & 2.4.2 Query methods with tuple bind parameter List<String[]> does no longer work Jul 22, 2024
@mp911de mp911de added this to the 3.2.9 (2023.1.9) milestone Jul 22, 2024
@mp911de mp911de added type: regression A regression from a previous release and removed type: bug A general bug labels Jul 22, 2024
mp911de added a commit that referenced this issue Jul 22, 2024
Refactor convertAndAddParameter method to writeValue(…) decoupling responsibilities for a clearer value conversion code path. Also, refactor collection conversion to functional callback-style and extend test assertions.

See #1323
Original pull request: #1838
mp911de pushed a commit that referenced this issue Jul 22, 2024
mp911de added a commit that referenced this issue Jul 22, 2024
Refactor convertAndAddParameter method to writeValue(…) decoupling responsibilities for a clearer value conversion code path. Also, refactor collection conversion to functional callback-style and extend test assertions.

See #1323
Original pull request: #1838
mp911de pushed a commit that referenced this issue Jul 22, 2024
mp911de added a commit that referenced this issue Jul 22, 2024
Refactor convertAndAddParameter method to writeValue(…) decoupling responsibilities for a clearer value conversion code path. Also, refactor collection conversion to functional callback-style and extend test assertions.

See #1323
Original pull request: #1838
mp911de added a commit that referenced this issue Jul 23, 2024
Correctly assign SQL type for tuples.

See #1323
Original pull request: #1838
mp911de added a commit that referenced this issue Jul 23, 2024
Correctly assign SQL type for tuples.

See #1323
Original pull request: #1838
mp911de added a commit that referenced this issue Jul 23, 2024
Correctly assign SQL type for tuples.

See #1323
Original pull request: #1838
mp911de added a commit that referenced this issue Jul 23, 2024
Correctly assign SQL type for tuples.

See #1323
Original pull request: #1838
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

Successfully merging a pull request may close this issue.

8 participants