pgjdbc/pgjdbc GitHub issues and pull requests (mirror)  
help / color / mirror / Atom feed
From: mjschwaiger (@mjschwaiger) <[email protected]>
To: pgjdbc/pgjdbc <[email protected]>
Subject: [pgjdbc/pgjdbc] issue #3910: Connection parameter cleanupSavepoints=true does not work with oid/blob column
Date: Fri, 16 Jan 2026 17:44:38 +0000
Message-ID: <[email protected]> (raw)

**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.
```

view thread (5+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: github://pgjdbc/pgjdbc
  Cc: [email protected], [email protected]
  Subject: Re: [pgjdbc/pgjdbc] issue #3910: Connection parameter cleanupSavepoints=true does not work with oid/blob column
  In-Reply-To: <<[email protected]>>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox