Message-ID: From: "mjschwaiger (@mjschwaiger)" To: "pgjdbc/pgjdbc" Date: Fri, 16 Jan 2026 17:44:38 +0000 Subject: [pgjdbc/pgjdbc] issue #3910: Connection parameter cleanupSavepoints=true does not work with oid/blob column List-Id: X-GitHub-Author-Id: 946648 X-GitHub-Author-Login: mjschwaiger X-GitHub-Issue: 3910 X-GitHub-Repo: pgjdbc/pgjdbc X-GitHub-State: closed X-GitHub-Type: issue X-GitHub-Url: https://github.com/pgjdbc/pgjdbc/issues/3910 Content-Type: text/plain; charset=utf-8 **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 : DROP TABLE IF EXISTS test_blob 2026-01-16 18:43:42.221 CET 1197 LOG: execute : CREATE TABLE test_blob (id BIGINT, doc OID) 2026-01-16 18:43:42.233 CET 1197 LOG: execute : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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.(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. ```