defer s.closemu.RUnlock()
var res Result
- for i := 0; i < maxBadConnRetries; i++ {
- dc, releaseConn, ds, err := s.connStmt(ctx)
+ strategy := cachedOrNewConn
+ for i := 0; i < maxBadConnRetries+1; i++ {
+ if i == maxBadConnRetries {
+ strategy = alwaysNewConn
+ }
+ dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
if err != nil {
if err == driver.ErrBadConn {
continue
// connStmt returns a free driver connection on which to execute the
// statement, a function to call to release the connection, and a
// statement bound to that connection.
-func (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(error), ds *driverStmt, err error) {
+func (s *Stmt) connStmt(ctx context.Context, strategy connReuseStrategy) (ci *driverConn, releaseConn func(error), ds *driverStmt, err error) {
if err = s.stickyErr; err != nil {
return
}
s.removeClosedStmtLocked()
s.mu.Unlock()
- dc, err := s.db.conn(ctx, cachedOrNewConn)
+ dc, err := s.db.conn(ctx, strategy)
if err != nil {
return nil, nil, nil, err
}
defer s.closemu.RUnlock()
var rowsi driver.Rows
- for i := 0; i < maxBadConnRetries; i++ {
- dc, releaseConn, ds, err := s.connStmt(ctx)
+ strategy := cachedOrNewConn
+ for i := 0; i < maxBadConnRetries+1; i++ {
+ if i == maxBadConnRetries {
+ strategy = alwaysNewConn
+ }
+ dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
if err != nil {
if err == driver.ErrBadConn {
continue
// Test cases where there's more than maxBadConnRetries bad connections in the
// pool (issue 8834)
func TestManyErrBadConn(t *testing.T) {
- manyErrBadConnSetup := func() *DB {
+ manyErrBadConnSetup := func(first ...func(db *DB)) *DB {
db := newTestDB(t, "people")
+ for _, f := range first {
+ f(db)
+ }
+
nconn := maxBadConnRetries + 1
db.SetMaxIdleConns(nconn)
db.SetMaxOpenConns(nconn)
t.Fatal(err)
}
+ // Stmt.Exec
+ db = manyErrBadConnSetup(func(db *DB) {
+ stmt, err = db.Prepare("INSERT|people|name=Julia,age=19")
+ if err != nil {
+ t.Fatal(err)
+ }
+ })
+ defer closeDB(t, db)
+ _, err = stmt.Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err = stmt.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ // Stmt.Query
+ db = manyErrBadConnSetup(func(db *DB) {
+ stmt, err = db.Prepare("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ })
+ defer closeDB(t, db)
+ rows, err = stmt.Query()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err = rows.Close(); err != nil {
+ t.Fatal(err)
+ }
+ if err = stmt.Close(); err != nil {
+ t.Fatal(err)
+ }
+
// Conn
db = manyErrBadConnSetup()
defer closeDB(t, db)