pgjdbc/pgjdbc GitHub issues and pull requests (mirror)
help / color / mirror / Atom feedFrom: jptx1234 (@jptx1234) <[email protected]>
To: pgjdbc/pgjdbc <[email protected]>
Subject: [pgjdbc/pgjdbc] issue #3957: Connection.isValid(timeout) hangs indefinitely after network interruption during PGCopyOutputStream COPY
Date: Wed, 11 Mar 2026 16:09:20 +0000
Message-ID: <[email protected]> (raw)
**Describe the issue**
When using `PGCopyOutputStream` to perform a COPY operation and the network is interrupted (e.g., network cable disconnected or PostgreSQL server restarted), calling `Connection.isValid(timeout)` after catching the exception hangs indefinitely instead of returning `false` within the specified timeout.
**Driver Version?**
42.7.10
**Java Version?**
21
**OS Version?**
Windows 11
**PostgreSQL Version?**
PostgreSQL 18
**To Reproduce**
1. Run the demo code below
2. During the COPY operation, interrupt the network (disconnect and reconnect network cable, or restart PostgreSQL server)
3. Observe that `conn.isValid(5)` hangs indefinitely instead of returning within 5 seconds
**Expected behaviour**
`Connection.isValid(5)` should return `false` within 5 seconds after network interruption.
**Actual behaviour**
`Connection.isValid(5)` hangs indefinitely and never returns.
**Logs**
Thread dump captured via `jstack -l <pid>` shows the main thread is stuck waiting on a lock in `QueryExecutorImpl.waitOnLock()`
```
"main" #1 [28072] prio=5 os_prio=0 cpu=343.75ms elapsed=21.93s tid=0x0000025914a32250 nid=28072 waiting on condition [0x000000dc522fe000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
- parking to wait for <0x00000006239b2788> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:371)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block([email protected]/AbstractQueuedSynchronizer.java:519)
at java.util.concurrent.ForkJoinPool.unmanagedBlock([email protected]/ForkJoinPool.java:3780)
at java.util.concurrent.ForkJoinPool.managedBlock([email protected]/ForkJoinPool.java:3725)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await([email protected]/AbstractQueuedSynchronizer.java:1712)
at org.postgresql.core.v3.QueryExecutorImpl.waitOnLock(QueryExecutorImpl.java:295)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:395)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:526)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:436)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:358)
at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:343)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:319)
at org.postgresql.jdbc.PgConnection.isValid(PgConnection.java:1584)
at io.github.jptx1234.pgjdbc_copy_demo.PgjdbcCopyDemoStream.copyData(PgjdbcCopyDemoStream.java:55)
at io.github.jptx1234.pgjdbc_copy_demo.PgjdbcCopyDemoStream.main(PgjdbcCopyDemoStream.java:29)
Locked ownable synchronizers:
- <0x00000006251520f0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
```
**Minimal Reproducible Example**
```java
import org.postgresql.copy.PGCopyOutputStream;
import org.postgresql.jdbc.PgConnection;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.UUID;
public class PgjdbcCopyDemoStream {
private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres";
private static final String DB_USER = "postgres";
private static final String DB_PASSWORD = "password";
private static final String TABLE_NAME = "copy_test";
public static void main(String[] args) throws Exception {
try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
createTable(conn);
copyData(conn);
}
}
private static void createTable(Connection conn) throws Exception {
try (Statement stmt = conn.createStatement()) {
stmt.execute("DROP TABLE IF EXISTS " + TABLE_NAME);
stmt.execute("CREATE TABLE " + TABLE_NAME + " (id SERIAL PRIMARY KEY, data TEXT)");
}
}
private static void copyData(Connection conn) throws Exception {
String copySql = "COPY " + TABLE_NAME + " (data) FROM STDIN WITH (FORMAT CSV)";
try (PGCopyOutputStream copyOut = new PGCopyOutputStream(conn.unwrap(PgConnection.class), copySql)) {
System.out.println("Start copying. Please interrupt network or restart PostgreSQL server.");
// Interrupt network during this phase
for (int i = 0; i < 500; i++) {
copyOut.write((UUID.randomUUID() + "\n").getBytes(StandardCharsets.UTF_8));
copyOut.flush();
Thread.sleep(100);
}
} catch (Exception e) {
System.err.println("COPY failed: " + e.getMessage());
System.out.println("Check isValid(5)");
// conn.isValid(5) should return false within 5 seconds, but hangs indefinitely
System.out.println("isValid: " + conn.isValid(5));
}
}
}
view thread (2+ 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 #3957: Connection.isValid(timeout) hangs indefinitely after network interruption during PGCopyOutputStream COPY
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