allowAny bool
}
+type fakeError struct {
+ Message string
+ Wrapped error
+}
+
+func (err fakeError) Error() string {
+ return err.Message
+}
+
+func (err fakeError) Unwrap() error {
+ return err.Wrapped
+}
+
type table struct {
mu sync.Mutex
colname []string
func (c *fakeConn) Begin() (driver.Tx, error) {
if c.isBad() {
- return nil, driver.ErrBadConn
+ return nil, fakeError{Wrapped: driver.ErrBadConn}
}
if c.currTx != nil {
return nil, errors.New("fakedb: already in a transaction")
c.dirtySession = false
c.currTx = nil
if c.isBad() {
- return driver.ErrBadConn
+ return fakeError{Message: "Reset Session: bad conn", Wrapped: driver.ErrBadConn}
}
return nil
}
}
if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) {
- return nil, driver.ErrBadConn
+ return nil, fakeError{Message: "Preapre: Sticky Bad", Wrapped: driver.ErrBadConn}
}
c.touchMem()
}
if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) {
- return nil, driver.ErrBadConn
+ return nil, fakeError{Message: "Exec: Sticky Bad", Wrapped: driver.ErrBadConn}
}
if s.c.isDirtyAndMark() {
return nil, errFakeConnSessionDirty
}
if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) {
- return nil, driver.ErrBadConn
+ return nil, fakeError{Message: "Query: Sticky Bad", Wrapped: driver.ErrBadConn}
}
if s.c.isDirtyAndMark() {
return nil, errFakeConnSessionDirty
func (tx *fakeTx) Commit() error {
tx.c.currTx = nil
if hookCommitBadConn != nil && hookCommitBadConn() {
- return driver.ErrBadConn
+ return fakeError{Message: "Commit: Hook Bad Conn", Wrapped: driver.ErrBadConn}
}
tx.c.touchMem()
return nil
func (tx *fakeTx) Rollback() error {
tx.c.currTx = nil
if hookRollbackBadConn != nil && hookRollbackBadConn() {
- return driver.ErrBadConn
+ return fakeError{Message: "Rollback: Hook Bad Conn", Wrapped: driver.ErrBadConn}
}
tx.c.touchMem()
return nil
func (db *DB) PingContext(ctx context.Context) error {
var dc *driverConn
var err error
-
+ var isBadConn bool
for i := 0; i < maxBadConnRetries; i++ {
dc, err = db.conn(ctx, cachedOrNewConn)
- if err != driver.ErrBadConn {
+ isBadConn = errors.Is(err, driver.ErrBadConn)
+ if !isBadConn {
break
}
}
- if err == driver.ErrBadConn {
+ if isBadConn {
dc, err = db.conn(ctx, alwaysNewConn)
}
if err != nil {
db.mu.Unlock()
// Reset the session if required.
- if err := conn.resetSession(ctx); err == driver.ErrBadConn {
+ if err := conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) {
conn.Close()
- return nil, driver.ErrBadConn
+ return nil, err
}
return conn, nil
}
// Reset the session if required.
- if err := ret.conn.resetSession(ctx); err == driver.ErrBadConn {
+ if err := ret.conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) {
ret.conn.Close()
- return nil, driver.ErrBadConn
+ return nil, err
}
return ret.conn, ret.err
}
// putConn adds a connection to the db's free pool.
// err is optionally the last error that occurred on this connection.
func (db *DB) putConn(dc *driverConn, err error, resetSession bool) {
- if err != driver.ErrBadConn {
+ if !errors.Is(err, driver.ErrBadConn) {
if !dc.validateConnection(resetSession) {
err = driver.ErrBadConn
}
panic("sql: connection returned that was never out")
}
- if err != driver.ErrBadConn && dc.expired(db.maxLifetime) {
+ if !errors.Is(err, driver.ErrBadConn) && dc.expired(db.maxLifetime) {
db.maxLifetimeClosed++
err = driver.ErrBadConn
}
}
dc.onPut = nil
- if err == driver.ErrBadConn {
+ if errors.Is(err, driver.ErrBadConn) {
// Don't reuse bad connections.
// Since the conn is considered bad and is being discarded, treat it
// as closed. Don't decrement the open count here, finalClose will
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
var stmt *Stmt
var err error
+ var isBadConn bool
for i := 0; i < maxBadConnRetries; i++ {
stmt, err = db.prepare(ctx, query, cachedOrNewConn)
- if err != driver.ErrBadConn {
+ isBadConn = errors.Is(err, driver.ErrBadConn)
+ if !isBadConn {
break
}
}
- if err == driver.ErrBadConn {
+ if isBadConn {
return db.prepare(ctx, query, alwaysNewConn)
}
return stmt, err
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
var res Result
var err error
+ var isBadConn bool
for i := 0; i < maxBadConnRetries; i++ {
res, err = db.exec(ctx, query, args, cachedOrNewConn)
- if err != driver.ErrBadConn {
+ isBadConn = errors.Is(err, driver.ErrBadConn)
+ if !isBadConn {
break
}
}
- if err == driver.ErrBadConn {
+ if isBadConn {
return db.exec(ctx, query, args, alwaysNewConn)
}
return res, err
func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
var rows *Rows
var err error
+ var isBadConn bool
for i := 0; i < maxBadConnRetries; i++ {
rows, err = db.query(ctx, query, args, cachedOrNewConn)
- if err != driver.ErrBadConn {
+ isBadConn = errors.Is(err, driver.ErrBadConn)
+ if !isBadConn {
break
}
}
- if err == driver.ErrBadConn {
+ if isBadConn {
return db.query(ctx, query, args, alwaysNewConn)
}
return rows, err
func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
var tx *Tx
var err error
+ var isBadConn bool
for i := 0; i < maxBadConnRetries; i++ {
tx, err = db.begin(ctx, opts, cachedOrNewConn)
- if err != driver.ErrBadConn {
+ isBadConn = errors.Is(err, driver.ErrBadConn)
+ if !isBadConn {
break
}
}
- if err == driver.ErrBadConn {
+ if isBadConn {
return db.begin(ctx, opts, alwaysNewConn)
}
return tx, err
func (db *DB) Conn(ctx context.Context) (*Conn, error) {
var dc *driverConn
var err error
+ var isBadConn bool
for i := 0; i < maxBadConnRetries; i++ {
dc, err = db.conn(ctx, cachedOrNewConn)
- if err != driver.ErrBadConn {
+ isBadConn = errors.Is(err, driver.ErrBadConn)
+ if !isBadConn {
break
}
}
- if err == driver.ErrBadConn {
+ if isBadConn {
dc, err = db.conn(ctx, alwaysNewConn)
}
if err != nil {
// Raw executes f exposing the underlying driver connection for the
// duration of f. The driverConn must not be used outside of f.
//
-// Once f returns and err is not equal to driver.ErrBadConn, the Conn will
-// continue to be usable until Conn.Close is called.
+// Once f returns and err is not driver.ErrBadConn, the Conn will continue to be usable
+// until Conn.Close is called.
func (c *Conn) Raw(f func(driverConn interface{}) error) (err error) {
var dc *driverConn
var release releaseConn
// as the sql operation is done with the dc.
func (c *Conn) closemuRUnlockCondReleaseConn(err error) {
c.closemu.RUnlock()
- if err == driver.ErrBadConn {
+ if errors.Is(err, driver.ErrBadConn) {
c.close(err)
}
}
withLock(tx.dc, func() {
err = tx.txi.Commit()
})
- if err != driver.ErrBadConn {
+ if !errors.Is(err, driver.ErrBadConn) {
tx.closePrepared()
}
tx.close(err)
withLock(tx.dc, func() {
err = tx.txi.Rollback()
})
- if err != driver.ErrBadConn {
+ if !errors.Is(err, driver.ErrBadConn) {
tx.closePrepared()
}
if discardConn {
}
dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
if err != nil {
- if err == driver.ErrBadConn {
+ if errors.Is(err, driver.ErrBadConn) {
continue
}
return nil, err
res, err = resultFromStatement(ctx, dc.ci, ds, args...)
releaseConn(err)
- if err != driver.ErrBadConn {
+ if !errors.Is(err, driver.ErrBadConn) {
return res, err
}
}
}
dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
if err != nil {
- if err == driver.ErrBadConn {
+ if errors.Is(err, driver.ErrBadConn) {
continue
}
return nil, err
}
releaseConn(err)
- if err != driver.ErrBadConn {
+ if !errors.Is(err, driver.ErrBadConn) {
return nil, err
}
}