Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion c/driver/postgresql/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ Status MakeStatus(PGresult* result, const char* format_string, Args&&... args) {
}

Status status(code, message);
status.SetSqlState(sqlstate);
if (sqlstate) {
status.SetSqlState(sqlstate);
}
for (const auto& field : kDetailFields) {
const char* value = PQresultErrorField(result, field.code);
if (value) {
Expand Down
29 changes: 29 additions & 0 deletions python/adbc_driver_postgresql/tests/test_dbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,32 @@ def test_connect_conn_kwargs_db_schema(postgres_uri: str, postgres: dbapi.Connec
with dbapi.connect(postgres_uri, conn_kwargs={schema_key: schema_name}) as conn:
option_value = conn.adbc_connection.get_option(schema_key)
assert option_value == schema_name


def test_server_terminates_connection(postgres_uri: str) -> None:
"""Test that driver handles server terminating the connection gracefully.

Reproduces: https://github.com/apache/arrow-adbc/issues/3878
When the server terminates a connection, the driver should return an error
instead of crashing with a segfault.
"""
with dbapi.connect(postgres_uri) as conn1:
with dbapi.connect(postgres_uri) as conn2:
# Get the backend PID of conn2
with conn2.cursor() as cur:
cur.execute("SELECT pg_backend_pid()")
row = cur.fetchone()
assert row is not None
backend_pid = row[0]
conn2.commit()

# simulate a server side termination of a connection2
with conn1.cursor() as cur:
cur.execute(f"SELECT pg_terminate_backend({backend_pid})")
conn1.commit()

# Try to execute a query on the terminated connection
# This should raise an exception, NOT crash with a segfault
with pytest.raises(Exception):
with conn2.cursor() as cur:
cur.execute("SELECT 1")
Loading