-
Notifications
You must be signed in to change notification settings - Fork 624
Closed
Closed
Copy link
Labels
Description
JPQL UPDATE queries that attempt to set an embedded object to null fail in PostgreSQL due to type inference issues with null parameters. EclipseLink generates SQL that PostgreSQL interprets as assigning varchar to integer columns, resulting in a type mismatch error.
Test snippet:
Line unitRadius = Line.of(0, 0, 1, 1);
tx.begin();
em.persist(unitRadius);
tx.commit();
tx.begin();
em.createQuery("UPDATE Line o SET o.pointB = ?1 WHERE (o.id=?2)")
.setParameter(1, null)
.setParameter(2, unitRadius.id)
.executeUpdate();
tx.commit();
Entity:
@Entity
public class Line {
@GeneratedValue
@Id
public Long id;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "x", column = @Column(name = "x_A")),
@AttributeOverride(name = "y", column = @Column(name = "y_A"))
})
@Column
public Point pointA;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "x", column = @Column(name = "x_B")),
@AttributeOverride(name = "y", column = @Column(name = "y_B"))
})
@Column
public Point pointB;
@Embeddable
public static class Point {
public int x;
public int y;
public static Point of(int x, int y) {
Point inst = new Point();
inst.x = x;
inst.y = y;
return inst;
}
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
return x == other.x && y == other.y;
}
}
public static Line of(int x1, int y1, int x2, int y2) {
Line inst = new Line();
inst.pointA = Point.of(x1, y1);
inst.pointB = Point.of(x2, y2);
return inst;
}
}
Queries generated and the complete stack trace:
[EL Info]: 2025.09.10 15:50:20.473--ServerSession(-267816401)--EclipseLink, version: Eclipse Persistence Services - 5.0.0-B10.v202508250733-7403fb4d27505a202052781d38a7d5324ff916bd
[EL Fine]: sql: 2025.09.10 15:50:20.600--ServerSession(-267816401)--Connection(839789395)--DROP TABLE LINE CASCADE
[EL Fine]: sql: 2025.09.10 15:50:20.612--ServerSession(-267816401)--Connection(839789395)--DELETE FROM SEQUENCE WHERE SEQ_NAME = 'SEQ_GEN'
[EL Fine]: sql: 2025.09.10 15:50:20.616--ServerSession(-267816401)--Connection(839789395)--CREATE TABLE LINE (ID BIGINT NOT NULL, x_A INTEGER, y_A INTEGER, x_B INTEGER, y_B INTEGER, PRIMARY KEY (ID))
[EL Fine]: sql: 2025.09.10 15:50:20.621--ServerSession(-267816401)--Connection(839789395)--INSERT INTO SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 0)
[EL Fine]: sql: 2025.09.10 15:50:20.630--ClientSession(-624557386)--Connection(839789395)--UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
bind => [50, SEQ_GEN]
[EL Fine]: sql: 2025.09.10 15:50:20.633--ClientSession(-624557386)--Connection(839789395)--SELECT SEQ_COUNT FROM SEQUENCE WHERE SEQ_NAME = ?
bind => [SEQ_GEN]
[EL Fine]: sql: 2025.09.10 15:50:20.637--ClientSession(-624557386)--Connection(839789395)--INSERT INTO LINE (ID, x_A, y_A, x_B, y_B) VALUES (?, ?, ?, ?, ?)
bind => [1, 0, 0, 1, 1]
[EL Fine]: sql: 2025.09.10 15:50:20.696--ClientSession(-624557386)--Connection(839789395)--UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)
bind => [null, null, 1]
[EL Fine]: sql: 2025.09.10 15:50:20.698--ClientSession(-624557386)--SELECT 1
[EL Warning]: 2025.09.10 15:50:20.698--UnitOfWork(1829996035)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 5.0.0-B10.v202508250733-7403fb4d27505a202052781d38a7d5324ff916bd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "y_b" is of type integer but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Position: 23
Error Code: 0
Call: UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)
bind => [null, null, 1]
Query: UpdateAllQuery(referenceClass=Line sql="UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)")
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.544 s <<< FAILURE! -- in com.oracle.jpa.bugtest.TestBug
[ERROR] com.oracle.jpa.bugtest.TestBug.testRTC305069 -- Time elapsed: 0.528 s <<< ERROR!
jakarta.persistence.PersistenceException:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 5.0.0-B10.v202508250733-7403fb4d27505a202052781d38a7d5324ff916bd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "y_b" is of type integer but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Position: 23
Error Code: 0
Call: UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)
bind => [null, null, 1]
Query: UpdateAllQuery(referenceClass=Line sql="UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)")
at org.eclipse.persistence.internal.jpa.QueryImpl.executeUpdate(QueryImpl.java:310)
at com.oracle.jpa.bugtest.TestBug.testRTC305069(TestBug.java:33)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:575)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56)
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184)
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148)
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:122)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 5.0.0-B10.v202508250733-7403fb4d27505a202052781d38a7d5324ff916bd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "y_b" is of type integer but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Position: 23
Error Code: 0
Call: UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)
bind => [null, null, 1]
Query: UpdateAllQuery(referenceClass=Line sql="UPDATE LINE SET y_B = ?, x_B = ? WHERE (ID = ?)")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:346)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1804)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:917)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:981)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:642)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:569)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2071)
at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:322)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:282)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:268)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelectCall(DatasourceCallQueryMechanism.java:325)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.updateAll(DatasourceCallQueryMechanism.java:940)
at org.eclipse.persistence.queries.UpdateAllQuery.executeDatabaseQuery(UpdateAllQuery.java:159)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:934)
at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:833)
at org.eclipse.persistence.queries.ModifyAllQuery.executeInUnitOfWork(ModifyAllQuery.java:153)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:3018)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1866)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1848)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1813)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeUpdate(QueryImpl.java:303)
... 72 more
Caused by: org.postgresql.util.PSQLException: ERROR: column "y_b" is of type integer but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Position: 23
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2725)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2412)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:371)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:502)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:419)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:194)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:155)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:909)
... 90 more