Subject: [pgjdbc/pgjdbc] issue #3910: Connection parameter cleanupSavepoints=true does not work with oid/blob column

From: "mjschwaiger (@mjschwaiger)" <[email-masked]>
Date: Fri, 16 Jan 2026 17:44:38 +0000

**Describe the issue**
PSQLException with message "Unknown Response Type C." occurs when a connection with parameter "cleanupSavepoints=true" (and "autosave=always") inserts or reads a record with an oid column (Blob object in Java).
PSQLException does not occur if just "autosave=always" is set.
https://jdbc.postgresql.org/documentation/use/

Related to #1407 / #1409.

**Driver Version?** 
42.7.8

**Java Version?**
JDK 21

**OS Version?**
Windows Server 2025

**PostgreSQL Version?**
Postgres 18.2-1

**To Reproduce**
See description and example code.

**Expected behaviour**
Insert and read of oid columns should also work when parameter "cleanupSavepoints=true" is set.

**Logs**
*PostgreSQL logs*
log_line_prefix = '%m %x '
log_statement = all
```
2026-01-16 18:43:25.837 CET 0 LOG:  database system is ready to accept connections
2026-01-16 18:43:42.172 CET 0 LOG:  statement: SET application_name = 'PostgreSQL JDBC Driver'
2026-01-16 18:43:42.216 CET 0 LOG:  statement: BEGIN
2026-01-16 18:43:42.218 CET 0 LOG:  execute <unnamed>: DROP TABLE IF EXISTS test_blob
2026-01-16 18:43:42.221 CET 1197 LOG:  execute <unnamed>: CREATE TABLE test_blob (id BIGINT, doc OID)
2026-01-16 18:43:42.233 CET 1197 LOG:  execute <unnamed>: SELECT p.proname,p.oid  FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n  WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND ( proname = 'lo_open' or proname = 'lo_close' or proname = 'lo_creat' or proname = 'lo_unlink' or proname = 'lo_lseek' or proname = 'lo_lseek64' or proname = 'lo_tell' or proname = 'lo_tell64' or proname = 'loread' or proname = 'lowrite' or proname = 'lo_truncate' or proname = 'lo_truncate64')
2026-01-16 18:43:42.241 CET 1197 LOG:  fastpath function call: "lo_creat" (OID 957)
2026-01-16 18:43:42.243 CET 1197 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.244 CET 1197 LOG:  fastpath function call: "lowrite" (OID 955)
2026-01-16 18:43:42.245 CET 1197 LOG:  fastpath function call: "lo_close" (OID 953)
2026-01-16 18:43:42.248 CET 1197 LOG:  execute <unnamed>: INSERT INTO test_blob (id, doc) VALUES ($1, $2)
2026-01-16 18:43:42.248 CET 1197 DETAIL:  Parameters: $1 = '1', $2 = '16776'
2026-01-16 18:43:42.249 CET 1197 LOG:  execute S_1: COMMIT
2026-01-16 18:43:42.257 CET 0 LOG:  statement: BEGIN
2026-01-16 18:43:42.257 CET 0 LOG:  execute <unnamed>: select id, doc from test_blob
2026-01-16 18:43:42.259 CET 0 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.259 CET 0 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.259 CET 0 LOG:  fastpath function call: "lo_lseek" (OID 956)
2026-01-16 18:43:42.259 CET 0 LOG:  fastpath function call: "loread" (OID 954)
2026-01-16 18:43:42.260 CET 0 LOG:  fastpath function call: "loread" (OID 954)
2026-01-16 18:43:42.260 CET 0 LOG:  execute <unnamed>: DROP TABLE IF EXISTS test_blob
2026-01-16 18:43:42.337 CET 0 LOG:  statement: SET application_name = 'PostgreSQL JDBC Driver'
2026-01-16 18:43:42.338 CET 0 LOG:  statement: BEGIN
2026-01-16 18:43:42.338 CET 0 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.338 CET 0 LOG:  execute <unnamed>: DROP TABLE IF EXISTS test_blob
2026-01-16 18:43:42.340 CET 1199 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.340 CET 1199 LOG:  execute <unnamed>: CREATE TABLE test_blob (id BIGINT, doc OID)
2026-01-16 18:43:42.342 CET 1199 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.345 CET 1199 LOG:  execute <unnamed>: SELECT p.proname,p.oid  FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n  WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND ( proname = 'lo_open' or proname = 'lo_close' or proname = 'lo_creat' or proname = 'lo_unlink' or proname = 'lo_lseek' or proname = 'lo_lseek64' or proname = 'lo_tell' or proname = 'lo_tell64' or proname = 'loread' or proname = 'lowrite' or proname = 'lo_truncate' or proname = 'lo_truncate64')
2026-01-16 18:43:42.345 CET 1199 LOG:  fastpath function call: "lo_creat" (OID 957)
2026-01-16 18:43:42.346 CET 1199 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.346 CET 1199 LOG:  fastpath function call: "lowrite" (OID 955)
2026-01-16 18:43:42.347 CET 1199 LOG:  fastpath function call: "lo_close" (OID 953)
2026-01-16 18:43:42.347 CET 1199 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.348 CET 1199 LOG:  execute <unnamed>: INSERT INTO test_blob (id, doc) VALUES ($1, $2)
2026-01-16 18:43:42.348 CET 1199 DETAIL:  Parameters: $1 = '1', $2 = '16780'
2026-01-16 18:43:42.348 CET 1199 LOG:  execute S_1: COMMIT
2026-01-16 18:43:42.351 CET 0 LOG:  statement: BEGIN
2026-01-16 18:43:42.351 CET 0 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.351 CET 0 LOG:  execute <unnamed>: select id, doc from test_blob
2026-01-16 18:43:42.352 CET 0 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.352 CET 0 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.352 CET 0 LOG:  fastpath function call: "lo_lseek" (OID 956)
2026-01-16 18:43:42.352 CET 0 LOG:  fastpath function call: "loread" (OID 954)
2026-01-16 18:43:42.353 CET 0 LOG:  fastpath function call: "loread" (OID 954)
2026-01-16 18:43:42.353 CET 0 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.353 CET 0 LOG:  execute <unnamed>: DROP TABLE IF EXISTS test_blob
2026-01-16 18:43:42.429 CET 0 LOG:  statement: SET application_name = 'PostgreSQL JDBC Driver'
2026-01-16 18:43:42.430 CET 0 LOG:  statement: BEGIN
2026-01-16 18:43:42.430 CET 0 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.433 CET 0 LOG:  execute <unnamed>: SELECT p.proname,p.oid  FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n  WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND ( proname = 'lo_open' or proname = 'lo_close' or proname = 'lo_creat' or proname = 'lo_unlink' or proname = 'lo_lseek' or proname = 'lo_lseek64' or proname = 'lo_tell' or proname = 'lo_tell64' or proname = 'loread' or proname = 'lowrite' or proname = 'lo_truncate' or proname = 'lo_truncate64')
2026-01-16 18:43:42.433 CET 0 LOG:  statement: RELEASE SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.434 CET 0 LOG:  fastpath function call: "lo_creat" (OID 957)
2026-01-16 18:43:42.506 CET 0 LOG:  statement: SET application_name = 'PostgreSQL JDBC Driver'
2026-01-16 18:43:42.507 CET 0 LOG:  statement: BEGIN
2026-01-16 18:43:42.507 CET 0 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.508 CET 0 LOG:  execute <unnamed>: select id, doc from test_blob
2026-01-16 18:43:42.508 CET 0 LOG:  statement: RELEASE SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.508 CET 0 LOG:  statement: SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.510 CET 0 LOG:  execute <unnamed>: SELECT p.proname,p.oid  FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n  WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND ( proname = 'lo_open' or proname = 'lo_close' or proname = 'lo_creat' or proname = 'lo_unlink' or proname = 'lo_lseek' or proname = 'lo_lseek64' or proname = 'lo_tell' or proname = 'lo_tell64' or proname = 'loread' or proname = 'lowrite' or proname = 'lo_truncate' or proname = 'lo_truncate64')
2026-01-16 18:43:42.511 CET 0 LOG:  statement: RELEASE SAVEPOINT PGJDBC_AUTOSAVE
2026-01-16 18:43:42.511 CET 0 LOG:  fastpath function call: "lo_open" (OID 952)
2026-01-16 18:43:42.512 CET 0 LOG:  could not receive data from client: An established connection was aborted by the software in your host machine.
	
2026-01-16 18:43:42.512 CET 0 LOG:  unexpected EOF on client connection with an open transaction
```

*Stacktrace of exception when inserting oid column:*
```
org.postgresql.util.PSQLException: Unknown Response Type C.
	at org.postgresql.core.v3.QueryExecutorImpl.receiveFastpathResult(QueryExecutorImpl.java:937)
	at org.postgresql.core.v3.QueryExecutorImpl.fastpathCall(QueryExecutorImpl.java:669)
	at org.postgresql.fastpath.Fastpath.fastpath(Fastpath.java:106)
	at org.postgresql.fastpath.Fastpath.fastpath(Fastpath.java:149)
	at org.postgresql.fastpath.Fastpath.getInteger(Fastpath.java:161)
	at org.postgresql.fastpath.Fastpath.getOID(Fastpath.java:212)
	at org.postgresql.largeobject.LargeObjectManager.createLO(LargeObjectManager.java:290)
	at org.postgresql.largeobject.LargeObjectManager.createLO(LargeObjectManager.java:273)
	at TestPgCleanupSavepointsWithBlob.testPgWithBlob(TestPgCleanupSavepointsWithBlob.java:54)
	at TestPgCleanupSavepointsWithBlob.main(TestPgCleanupSavepointsWithBlob.java:22)
```

*Stacktrace of exception when reading oid column:*
```
org.postgresql.util.PSQLException: Unknown Response Type C.
	at org.postgresql.core.v3.QueryExecutorImpl.receiveFastpathResult(QueryExecutorImpl.java:937)
	at org.postgresql.core.v3.QueryExecutorImpl.fastpathCall(QueryExecutorImpl.java:669)
	at org.postgresql.fastpath.Fastpath.fastpath(Fastpath.java:106)
	at org.postgresql.fastpath.Fastpath.fastpath(Fastpath.java:149)
	at org.postgresql.fastpath.Fastpath.getInteger(Fastpath.java:161)
	at org.postgresql.largeobject.LargeObject.<init>(LargeObject.java:107)
	at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:247)
	at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:230)
	at org.postgresql.jdbc.AbstractBlobClob.getLo(AbstractBlobClob.java:288)
	at org.postgresql.jdbc.AbstractBlobClob.getBinaryStream(AbstractBlobClob.java:127)
	at TestPgCleanupSavepointsWithBlob.testPgWithBlob(TestPgCleanupSavepointsWithBlob.java:75)
	at TestPgCleanupSavepointsWithBlob.main(TestPgCleanupSavepointsWithBlob.java:24)
```

**Example code**
Code to replicate these errors:
```
import org.postgresql.PGConnection;
import org.postgresql.largeobject.LargeObject;
import org.postgresql.largeobject.LargeObjectManager;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Locale;

public class TestPgCleanupSavepointsWithBlob {
    private static final String DB_URL = "jdbc:postgresql://localhost:5432/test";
    private static final String DB_USER = "testuser";
    private static final String DB_PASSWORD = "testuser";

    public static void main(String[] args) {
        testPgWithBlob("",
                true, true, true, true, true);
        testPgWithBlob("?autosave=always&cleanupSavepoints=false",
                true, true, true, true, true);
        testPgWithBlob("?autosave=always&cleanupSavepoints=true",
                false, false, true, false, false); // insert record with blob (oid column)
        testPgWithBlob("?autosave=always&cleanupSavepoints=true",
                false, false, false, true, false); // query record with blob (oid column)
    }

    private static void testPgWithBlob(String dbUrlProperties, boolean dropTableStart,
                                       boolean createTable, boolean insertData,
                                       boolean executeQuery, boolean dropTableEnd) {
        Locale.setDefault(Locale.ENGLISH);
        try {
            String dbUrlWithProp = DB_URL + dbUrlProperties;
            System.out.println("Connecting to database [" + dbUrlWithProp + "] ...");
            try (Connection connection = DriverManager.getConnection(dbUrlWithProp, DB_USER, DB_PASSWORD)) {
                System.out.println("Connected successfully");
                System.out.println("Set autocommit=false");
                connection.setAutoCommit(false);

                try (Statement statement = connection.createStatement()) {
                    if (dropTableStart) {
                        System.out.println("Drop table (start) ...");
                        statement.executeUpdate("DROP TABLE IF EXISTS test_blob");
                    }

                    if (createTable) {
                        System.out.println("Create table ...");
                        statement.executeUpdate("CREATE TABLE test_blob (id BIGINT, doc OID)");
                    }

                    if (insertData) {
                        System.out.println("Insert record ...");
                        LargeObjectManager lom = ((PGConnection) connection).getLargeObjectAPI();
                        long oid = lom.createLO();
                        LargeObject lobj = lom.open(oid, LargeObjectManager.WRITE);
                        byte[] bytes = {0x48, 0x65, 0x6C, 0x6C, 0x6F};
                        lobj.write(bytes);
                        lobj.close();

                        String sql = "INSERT INTO test_blob (id, doc) VALUES (?, ?)";
                        try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
                            pstmt.setInt(1, 1);
                            pstmt.setLong(2, oid);
                            pstmt.executeUpdate();
                        }
                        connection.commit();
                    }

                    if (executeQuery) {
                        System.out.println("Executing query ...");
                        try (ResultSet resultSet = statement.executeQuery("select id, doc from test_blob")) {
                            while (resultSet.next()) {
                                System.out.println("[id] -> " + resultSet.getString(1));
                                Blob content = resultSet.getBlob(2);
                                InputStream contentInputStream = new BufferedInputStream(content.getBinaryStream());
                                try {
                                    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                                    int nRead;
                                    byte[] data = new byte[1024];
                                    while ((nRead = contentInputStream.read(data, 0, data.length)) != -1) {
                                        buffer.write(data, 0, nRead);
                                    }
                                    byte[] contentArray = buffer.toByteArray();
                                    System.out.println("[doc] -> contentArray.length=" + contentArray.length);
                                } catch (IOException e) {
                                    System.err.println("I/O error occurred!");
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                    if (dropTableEnd) {
                        System.out.println("Drop table (end) ...");
                        statement.executeUpdate("DROP TABLE IF EXISTS test_blob");
                    }
                }
            }
        } catch (SQLException e) {
            System.out.println("### Database error occurred - " + e.getMessage());
            System.err.println("### Database error occurred - " + e.getMessage());
            e.printStackTrace();
        }
        System.out.println(" - - - - - - - - - - - - - ");
    }
}
```

*Output/result of execution of example code*
```
Connecting to database [jdbc:postgresql://localhost:5432/test] ...
Connected successfully
Set autocommit=false
Drop table (start) ...
Create table ...
Insert record ...
Executing query ...
[id] -> 1
[doc] -> contentArray.length=5
Drop table (end) ...
 - - - - - - - - - - - - - 
Connecting to database [jdbc:postgresql://localhost:5432/test?autosave=always&cleanupSavepoints=false] ...
Connected successfully
Set autocommit=false
Drop table (start) ...
Create table ...
Insert record ...
Executing query ...
[id] -> 1
[doc] -> contentArray.length=5
Drop table (end) ...
 - - - - - - - - - - - - - 
Connecting to database [jdbc:postgresql://localhost:5432/test?autosave=always&cleanupSavepoints=true] ...
Connected successfully
Set autocommit=false
Insert record ...
### Database error occurred: Unknown Response Type C.
 - - - - - - - - - - - - - 
Connecting to database [jdbc:postgresql://localhost:5432/test?autosave=always&cleanupSavepoints=true] ...
Connected successfully
Set autocommit=false
Executing query ...
[id] -> 1
### Database error occurred: Unknown Response Type C.
```

---

From: "mjschwaiger (@mjschwaiger)" <[email-masked]>
Date: Mon, 19 Jan 2026 08:27:08 +0000

@vlsi 
Thank you for your prompt response and for resolving this issue. 

Tested with following Gradle configuration successfully. Looks good to me! 

But still wondering that no one else encountered this issue, or if there are others who have experienced something similar.

Any timeline when 42.7.10 is going to be released?

`settings.gradle`
```
dependencyResolutionManagement {
    repositories {
       maven {
            name = 'sonatype-snapshots'
            url = 'https://central.sonatype.com/repository/maven-snapshots'
            mavenContent {
                snapshotsOnly()
            }
        }
    }
}
```

`build.gradle`
```
dependencies {
    implementation 'org.postgresql:postgresql:42.7.10-SNAPSHOT'
}
```

Results of executing TestPgCleanupSavepointsWithBlob.main():
```

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Mon, 19 Jan 2026 10:37:24 +0000

Well 42.7.9 was just released so at the moment there is no timeline to release the next version.

---

From: "mjschwaiger (@mjschwaiger)" <[email-masked]>
Date: Mon, 19 Jan 2026 11:48:52 +0000

> Well 42.7.9 was just released so at the moment there is no timeline to release the next version.

Yeah, I saw that the last release was just a few days ago.
If you can, it'd be great to get this fix in a new release by the end of March 2026.

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Mon, 19 Jan 2026 13:54:04 +0000

Many thanks for testing the fix.

I guess the combination of `autosave + LargeObjectManager` is not used as much as the default non-autosave mode, so you might be the first to discover or report the issue.

--

I realized we could add autosave=... to the randomized matrix, and it uncovered a couple of similar to LargeObjectManager issues (set transaction... and CopyManager): https://github.com/pgjdbc/pgjdbc/pull/3917