Skip to content

Commit cd36177

Browse files
authored
Merge branch 'jackc:master' into v5.7.6-fix
2 parents f4fee4b + eb1d23a commit cd36177

File tree

11 files changed

+149
-34
lines changed

11 files changed

+149
-34
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313

1414
strategy:
1515
matrix:
16-
go-version: ["1.23", "1.24"]
16+
go-version: ["1.24", "1.25"]
1717
pg-version: [13, 14, 15, 16, 17, cockroachdb]
1818
include:
1919
- pg-version: 13
@@ -125,7 +125,7 @@ jobs:
125125
runs-on: windows-latest
126126
strategy:
127127
matrix:
128-
go-version: ["1.23", "1.24"]
128+
go-version: ["1.24", "1.25"]
129129

130130
steps:
131131
- name: Setup PostgreSQL

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ See the presentation at Golang Estonia, [PGX Top to Bottom](https://www.youtube.
9292

9393
## Supported Go and PostgreSQL Versions
9494

95-
pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.23 and higher and PostgreSQL 13 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/).
95+
pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.24 and higher and PostgreSQL 13 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/).
9696

9797
## Version Policy
9898

@@ -186,6 +186,6 @@ Simple Golang implementation for transactional outbox pattern for PostgreSQL usi
186186

187187
Simplifies working with the pgx library, providing convenient scanning of nested structures.
188188

189-
## [https://github.com/KoNekoD/pgx-colon-query-rewriter](https://github.com/KoNekoD/pgx-colon-query-rewriter)
189+
### [https://github.com/KoNekoD/pgx-colon-query-rewriter](https://github.com/KoNekoD/pgx-colon-query-rewriter)
190190

191191
Implementation of the pgx query rewriter to use ':' instead of '@' in named query parameters.

batch.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,6 @@ func (br *pipelineBatchResults) Close() error {
404404

405405
if br.err == nil && br.lastRows != nil && br.lastRows.err != nil {
406406
br.err = br.lastRows.err
407-
return br.err
408407
}
409408

410409
if br.closed {

batch_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,44 @@ func TestConnSendBatchErrorDoesNotLeaveOrphanedPreparedStatement(t *testing.T) {
10221022
})
10231023
}
10241024

1025+
func TestSendBatchStatementTimeout(t *testing.T) {
1026+
t.Parallel()
1027+
1028+
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
1029+
defer cancel()
1030+
1031+
pgxtest.RunWithQueryExecModes(ctx, t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
1032+
batch := &pgx.Batch{}
1033+
batch.Queue("SET statement_timeout='1ms'")
1034+
batch.Queue("SELECT pg_sleep(10)")
1035+
1036+
br := conn.SendBatch(context.Background(), batch)
1037+
// set statement_timeout
1038+
_, err := br.Exec()
1039+
assert.NoError(t, err)
1040+
1041+
// get pg_sleep results
1042+
rows, err := br.Query()
1043+
assert.NoError(t, err)
1044+
1045+
// Consume rows and check error
1046+
for rows.Next() {
1047+
}
1048+
err = rows.Err()
1049+
assert.ErrorContains(t, err, "(SQLSTATE 57014)")
1050+
rows.Close()
1051+
1052+
// The last error should be repeated when closing the batch
1053+
err = br.Close()
1054+
assert.ErrorContains(t, err, "(SQLSTATE 57014)")
1055+
1056+
// Connection should be usable after the statement timeout in pipeline
1057+
_, err = conn.Exec(context.Background(), "Select 1")
1058+
assert.NoError(t, err)
1059+
})
1060+
1061+
}
1062+
10251063
func ExampleConn_SendBatch() {
10261064
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
10271065
defer cancel()

go.mod

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
module github.com/jackc/pgx/v5
22

3-
go 1.23.0
3+
go 1.24.0
44

55
require (
66
github.com/jackc/pgpassfile v1.0.0
77
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761
88
github.com/jackc/puddle/v2 v2.2.2
9-
github.com/stretchr/testify v1.8.1
10-
golang.org/x/crypto v0.37.0
11-
golang.org/x/sync v0.13.0
12-
golang.org/x/text v0.24.0
9+
github.com/stretchr/testify v1.11.1
10+
golang.org/x/sync v0.17.0
11+
golang.org/x/text v0.29.0
1312
)
1413

1514
require (

go.sum

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
2121
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
2222
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
2323
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
24-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
25-
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
2624
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
2725
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
28-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
29-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
30-
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
31-
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
32-
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
33-
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
34-
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
35-
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
36-
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
37-
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
26+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
27+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
28+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
29+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
30+
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
31+
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
3832
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3933
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
4034
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

pgconn/auth_scram.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package pgconn
1515
import (
1616
"bytes"
1717
"crypto/hmac"
18+
"crypto/pbkdf2"
1819
"crypto/rand"
1920
"crypto/sha256"
2021
"encoding/base64"
@@ -23,7 +24,6 @@ import (
2324
"strconv"
2425

2526
"github.com/jackc/pgx/v5/pgproto3"
26-
"golang.org/x/crypto/pbkdf2"
2727
"golang.org/x/text/secure/precis"
2828
)
2929

@@ -107,7 +107,7 @@ func (c *PgConn) rxSASLFinal() (*pgproto3.AuthenticationSASLFinal, error) {
107107

108108
type scramClient struct {
109109
serverAuthMechanisms []string
110-
password []byte
110+
password string
111111
clientNonce []byte
112112

113113
clientFirstMessageBare []byte
@@ -140,10 +140,10 @@ func newScramClient(serverAuthMechanisms []string, password string) (*scramClien
140140

141141
// precis.OpaqueString is equivalent to SASLprep for password.
142142
var err error
143-
sc.password, err = precis.OpaqueString.Bytes([]byte(password))
143+
sc.password, err = precis.OpaqueString.String(password)
144144
if err != nil {
145145
// PostgreSQL allows passwords invalid according to SCRAM / SASLprep.
146-
sc.password = []byte(password)
146+
sc.password = password
147147
}
148148

149149
buf := make([]byte, clientNonceLen)
@@ -220,7 +220,11 @@ func (sc *scramClient) recvServerFirstMessage(serverFirstMessage []byte) error {
220220
func (sc *scramClient) clientFinalMessage() string {
221221
clientFinalMessageWithoutProof := []byte(fmt.Sprintf("c=biws,r=%s", sc.clientAndServerNonce))
222222

223-
sc.saltedPassword = pbkdf2.Key([]byte(sc.password), sc.salt, sc.iterations, 32, sha256.New)
223+
var err error
224+
sc.saltedPassword, err = pbkdf2.Key(sha256.New, sc.password, sc.salt, sc.iterations, 32)
225+
if err != nil {
226+
panic(err) // This should never happen.
227+
}
224228
sc.authMessage = bytes.Join([][]byte{sc.clientFirstMessageBare, sc.serverFirstMessage, clientFinalMessageWithoutProof}, []byte(","))
225229

226230
clientProof := computeClientProof(sc.saltedPassword, sc.authMessage)

pgxpool/pool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
591591
// Try to acquire from the connection pool up to maxConns + 1 times, so that
592592
// any that fatal errors would empty the pool and still at least try 1 fresh
593593
// connection.
594-
for range p.maxConns + 1 {
594+
for range int(p.maxConns) + 1 {
595595
res, err := p.p.Acquire(ctx)
596596
if err != nil {
597597
return nil, err

pgxpool/pool_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"math"
78
"os"
89
"sync/atomic"
910
"testing"
@@ -245,6 +246,27 @@ func TestPoolAcquireChecksIdleConnsWithShouldPing(t *testing.T) {
245246
c.Release()
246247
}
247248

249+
// https://github.com/jackc/pgx/issues/2379
250+
func TestPoolAcquireWithMaxConnsEqualsMaxInt32(t *testing.T) {
251+
t.Parallel()
252+
253+
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
254+
defer cancel()
255+
256+
config, err := pgxpool.ParseConfig(os.Getenv("PGX_TEST_DATABASE"))
257+
require.NoError(t, err)
258+
259+
config.MaxConns = math.MaxInt32
260+
261+
pool, err := pgxpool.NewWithConfig(ctx, config)
262+
require.NoError(t, err)
263+
defer pool.Close()
264+
265+
c, err := pool.Acquire(ctx)
266+
require.NoError(t, err)
267+
c.Release()
268+
}
269+
248270
func TestPoolAcquireFunc(t *testing.T) {
249271
t.Parallel()
250272

stdlib/sql.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@ func init() {
124124
// OptionOpenDB options for configuring the driver when opening a new db pool.
125125
type OptionOpenDB func(*connector)
126126

127+
// ShouldPingParams are passed to OptionShouldPing to decide whether to ping before reusing a connection.
128+
type ShouldPingParams struct {
129+
// Conn is the underlying pgx connection.
130+
Conn *pgx.Conn
131+
// IdleDuration is how long it has been since ResetSession last ran.
132+
IdleDuration time.Duration
133+
}
134+
135+
// OptionShouldPing controls whether stdlib should issue a liveness ping before reusing a connection.
136+
// If the function returns true, stdlib will ping.
137+
// If it returns false, stdlib will skip the ping.
138+
// If not provided, default is ping only when IdleDuration > 1s.
139+
func OptionShouldPing(f func(context.Context, ShouldPingParams) bool) OptionOpenDB {
140+
return func(dc *connector) { dc.ShouldPing = f }
141+
}
142+
127143
// OptionBeforeConnect provides a callback for before connect. It is passed a shallow copy of the ConnConfig that will
128144
// be used to connect, so only its immediate members should be modified. Used only if db is opened with *pgx.ConnConfig.
129145
func OptionBeforeConnect(bc func(context.Context, *pgx.ConnConfig) error) OptionOpenDB {
@@ -231,6 +247,7 @@ type connector struct {
231247
BeforeConnect func(context.Context, *pgx.ConnConfig) error // function to call before creation of every new connection
232248
AfterConnect func(context.Context, *pgx.Conn) error // function to call after creation of every new connection
233249
ResetSession func(context.Context, *pgx.Conn) error // function is called before a connection is reused
250+
ShouldPing func(context.Context, ShouldPingParams) bool // function to decide if stdlib should ping before reusing a connection
234251
driver *Driver
235252
}
236253

@@ -282,6 +299,7 @@ func (c connector) Connect(ctx context.Context) (driver.Conn, error) {
282299
driver: c.driver,
283300
connConfig: connConfig,
284301
resetSessionFunc: c.ResetSession,
302+
shouldPing: c.ShouldPing,
285303
psRefCounts: make(map[*pgconn.StatementDescription]int),
286304
}, nil
287305
}
@@ -389,7 +407,8 @@ type Conn struct {
389407
close func(context.Context) error
390408
driver *Driver
391409
connConfig pgx.ConnConfig
392-
resetSessionFunc func(context.Context, *pgx.Conn) error // Function is called before a connection is reused
410+
resetSessionFunc func(context.Context, *pgx.Conn) error // Function is called before a connection is reused
411+
shouldPing func(context.Context, ShouldPingParams) bool // Function to decide if stdlib should ping before reusing a connection
393412
lastResetSessionTime time.Time
394413

395414
// psRefCounts contains reference counts for prepared statements. Prepare uses the underlying pgx logic to generate
@@ -537,11 +556,23 @@ func (c *Conn) ResetSession(ctx context.Context) error {
537556
}
538557

539558
now := time.Now()
540-
if now.Sub(c.lastResetSessionTime) > time.Second {
559+
idle := now.Sub(c.lastResetSessionTime)
560+
561+
doPing := idle > time.Second // default behavior: ping only if idle > 1s
562+
563+
if c.shouldPing != nil {
564+
doPing = c.shouldPing(ctx, ShouldPingParams{
565+
Conn: c.conn,
566+
IdleDuration: idle,
567+
})
568+
}
569+
570+
if doPing {
541571
if err := c.conn.PgConn().Ping(ctx); err != nil {
542572
return driver.ErrBadConn
543573
}
544574
}
575+
545576
c.lastResetSessionTime = now
546577

547578
return c.resetSessionFunc(ctx, c.conn)

0 commit comments

Comments
 (0)