Reputation: 11
I am using JPA (Implementation EclipseLink) together with a PostgreSQL database. When using native queries, I get errors when using (named) query parameters that are resolved to Lists, for example "in (#ids)".
Let's say I have a table "car" with columns "id" and "name". I want to find the names of all cars with ids from a set "ids". Then I would utilize a native query with JPA like so:
final String sql = """
select c.name
from cars c
where c.id = (#ids)""";
final List<String> result = em.createNativeQuery(sql)
.setParameter("ids", new ArrayList<>(ids))
.getResultList();
When executing said query I get the following error:
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.12.v20230209-e5c4074ef3): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: Der in SQL für eine Instanz von java.util.ArrayList zu verwendende Datentyp kann nicht abgeleitet werden. Benutzen Sie 'setObject()' mit einem expliziten Typ, um ihn festzulegen.
Error Code: 0
Call: select c.name
from cars c
where c.id = (?)
bind => [[1]]
Query: DataReadQuery(sql=" select c.name
from cars c
where c.id = (?)")
at app//org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:342)
at app//org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:700)
at app//org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:567)
at app//org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2105)
at app//org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:313)
at app//org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:275)
at app//org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:261)
at app//org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:345)
at app//org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelect(DatasourceCallQueryMechanism.java:327)
at app//org.eclipse.persistence.queries.DataReadQuery.executeNonCursor(DataReadQuery.java:199)
at app//org.eclipse.persistence.queries.DataReadQuery.executeDatabaseQuery(DataReadQuery.java:154)
at app//org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:913)
at app//org.eclipse.persistence.queries.DataReadQuery.execute(DataReadQuery.java:139)
at app//org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:812)
at app//org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:3004)
at app//org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1898)
at app//org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1880)
at app//org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1845)
at app//org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:262)
... 162 more
Caused by: org.postgresql.util.PSQLException: Der in SQL für eine Instanz von java.util.ArrayList zu verwendende Datentyp kann nicht abgeleitet werden. Benutzen Sie 'setObject()' mit einem expliziten Typ, um ihn festzulegen.
at app//org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1051)
at app//org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.setParameterValueInDatabaseCall(DatabasePlatform.java:2703)
at app//org.eclipse.persistence.internal.databaseaccess.DatabaseCall.prepareStatement(DatabaseCall.java:791)
at app//org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:628)
... 179 more
Is anyone familiar with this error? Currently I am looking into Criteria API and Spring Data as possible workarounds.
EDIT: Manipulations of String literals is not an option (SQL Injection)
Versions:
-'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.12'
-'org.postgresql:postgresql:42.6.0'
Upvotes: 0
Views: 255
Reputation: 21145
What you are after is not supported in JPA or EclipseLink: JPA does not allow passing in parameters. Implementation wise, EclipseLink does not parse the SQL you provide in Native SQL queries, and instead will pass it to the driver as is to create a prepared statement. If you want to be able to expand your list into multiple parameters, use JPQL:
em.createQuery("select c.name from cars c where c.id in :idList")
.setParameter("idList", new ArrayList<>(ids))
.getResultList();
Upvotes: 0