Skip to content

JPQL Update with Null Embedded Object Fails on PostgreSQL Due to Type Mismatch #32848

@pardhiv-krishna

Description

@pardhiv-krishna

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

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions