From 77c1076d39f7da745ccbf0e13d06083bba589f64 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 1 Feb 2020 12:00:26 -0600 Subject: [PATCH] stdlib.ReleaseConn closes connections left in invalid state If a connection is in a transaction or has an open result set then close the connection when returning it to database/sql. When next database/sql attempts to use it the connection will return driver.ErrBadConn and database/sql will remove it from the pool. fixes #673 --- stdlib/sql.go | 6 ++++++ stdlib/sql_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/stdlib/sql.go b/stdlib/sql.go index f33a835e..e7e4b9a0 100644 --- a/stdlib/sql.go +++ b/stdlib/sql.go @@ -570,6 +570,12 @@ func ReleaseConn(db *sql.DB, conn *pgx.Conn) error { var tx *sql.Tx var ok bool + if conn.PgConn().IsBusy() || conn.PgConn().TxStatus() != 'I' { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + conn.Close(ctx) + } + fakeTxMutex.Lock() tx, ok = fakeTxConns[conn] if ok { diff --git a/stdlib/sql_test.go b/stdlib/sql_test.go index 99842e7f..ad9b6485 100644 --- a/stdlib/sql_test.go +++ b/stdlib/sql_test.go @@ -692,6 +692,39 @@ func TestAcquireConn(t *testing.T) { ensureConnValid(t, db) } +// https://github.com/jackc/pgx/issues/673 +func TestReleaseConnWithTxInProgress(t *testing.T) { + db := openDB(t) + defer closeDB(t, db) + + c1, err := stdlib.AcquireConn(db) + require.NoError(t, err) + + _, err = c1.Exec(context.Background(), "begin") + require.NoError(t, err) + + c1PID := c1.PgConn().PID() + + err = stdlib.ReleaseConn(db, c1) + require.NoError(t, err) + + c2, err := stdlib.AcquireConn(db) + require.NoError(t, err) + + c2PID := c2.PgConn().PID() + + err = stdlib.ReleaseConn(db, c2) + require.NoError(t, err) + + require.NotEqual(t, c1PID, c2PID) + + // Releasing a conn with a tx in progress should close the connection + stats := db.Stats() + require.Equal(t, 1, stats.OpenConnections) + + ensureConnValid(t, db) +} + func TestConnPingContextSuccess(t *testing.T) { db := openDB(t) defer closeDB(t, db)