From 608f39f426356884301835e89dbc26edae821c93 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 3 Jun 2023 07:39:56 -0500 Subject: [PATCH] Ensure pgxpool.Pool.QueryRow.Scan releases connection on panic Otherwise a connection would be leaked and closing the pool would block. https://github.com/jackc/pgx/issues/1628 --- pgxpool/pool_test.go | 19 +++++++++++++++++++ pgxpool/rows.go | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/pgxpool/pool_test.go b/pgxpool/pool_test.go index 30f742cd..2fa389ed 100644 --- a/pgxpool/pool_test.go +++ b/pgxpool/pool_test.go @@ -698,6 +698,25 @@ func TestPoolQueryRowErrNoRows(t *testing.T) { require.Equal(t, pgx.ErrNoRows, err) } +// https://github.com/jackc/pgx/issues/1628 +func TestPoolQueryRowScanPanicReleasesConnection(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + pool, err := pgxpool.New(ctx, os.Getenv("PGX_TEST_DATABASE")) + require.NoError(t, err) + defer pool.Close() + + require.Panics(t, func() { + var greeting *string + pool.QueryRow(ctx, "select 'Hello, world!'").Scan(greeting) // Note lack of &. This means that a typed nil is passed to Scan. + }) + + // If the connection is not released this will block forever in the defer pool.Close(). +} + func TestPoolSendBatch(t *testing.T) { t.Parallel() diff --git a/pgxpool/rows.go b/pgxpool/rows.go index 2b11ecd3..f834b7ec 100644 --- a/pgxpool/rows.go +++ b/pgxpool/rows.go @@ -101,7 +101,14 @@ func (row *poolRow) Scan(dest ...any) error { return row.err } + panicked := true + defer func() { + if panicked && row.c != nil { + row.c.Release() + } + }() err := row.r.Scan(dest...) + panicked = false if row.c != nil { row.c.Release() }