Skip to content

Report dead connection when libpq has given up on it (#224) - #225

Open
davecramer wants to merge 1 commit into
mainfrom
fix-224-connection-dead
Open

davecramer wants to merge 1 commit into
mainfrom
fix-224-connection-dead

Conversation

@davecramer

Copy link
Copy Markdown
Contributor

Refs #224.

System.Data.Odbc closes an OdbcConnection after a failed call only when SQL_ATTR_CONNECTION_DEAD returns SQL_CD_TRUE. Otherwise it throws the driver's error and leaves State at Open, which is what #224 reports.

Changes

  • SQL_ATTR_CONNECTION_DEAD, in both PGAPI_GetConnectAttr and PGAPI_GetConnectOption, now also returns true when PQstatus() is CONNECTION_BAD. Before this, the answer came from conn->status alone. A connection libpq had already given up on was reported alive until some code path called CC_on_abort().
  • When PQsendQuery() fails in CC_send_query_append() and PQstatus() is CONNECTION_BAD, the driver now calls CC_on_abort(conn, CONN_DEAD). Before this, it set the error and kept the connection marked up, so every later query failed while the application kept the connection open.

What this does not establish

This PR doesn't confirm the root cause of scenario 2 in #224. Both messages in that report, "The connection is down" and "SQLExecDirectW unable due to the connection lost", appear only when conn->pqconn is NULL. After connect, the only code that clears pqconn is CC_on_abort(CONN_DEAD), which sets CONN_DOWN first, so SQL_ATTR_CONNECTION_DEAD should already have answered true. Telling which case the reporter hit needs a MyLog from a failing run, which records the status behind each SQL_ATTR_CONNECTION_DEAD answer.

Test

connection-dead terminates the test connection's backend from a second connection. It then checks SQL_ATTR_CONNECTION_DEAD before termination and after each of two failing queries. It passes with and without the driver change, because a terminated backend is detected through PQgetResult(), a path that already called CC_on_abort(). So it guards the dead-connection answer against regressions rather than reproducing the change. The PQsendQuery() failure path depends on socket timing and isn't exercised.

The full suite (68 tests) passes against PostgreSQL 18 on macOS.

System.Data.Odbc closes an OdbcConnection only when
SQL_ATTR_CONNECTION_DEAD returns SQL_CD_TRUE after a failed call.
The driver answered from conn->status alone, so a connection that
libpq had already marked CONNECTION_BAD was reported alive until some
code path called CC_on_abort().

One such path: when PQsendQuery() failed, CC_send_query_append() set
the error but left the connection marked up, so every later query
failed while the application kept the connection open.

SQL_ATTR_CONNECTION_DEAD now also returns true when PQstatus() is
CONNECTION_BAD, and a PQsendQuery() failure on a CONNECTION_BAD
connection now gives up the connection.

New connection-dead test terminates the test connection's backend from
a second connection and checks SQL_ATTR_CONNECTION_DEAD before and
after the next queries fail.

Assisted-By: Claude
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant