mirror of
https://github.com/golang/go
synced 2024-09-29 09:24:28 -06:00
database/sql: wrap errors with %w in driverArgsConnLocked
Use fmt.Errorf %w verb to wrap errors in driverArgsConnLocked,
which allows for easier unwrapping and checking of error types.
Add tests in sql_test.go to ensure that Stmt.Exec and Stmt.Query
correctly wrap underlying Valuer errors, adhering to the new change.
Fixes #64707.
Change-Id: Id9f80e265735d0849ee7abba63e58e4c26e658ad
GitHub-Last-Rev: 0df367e0fb
GitHub-Pull-Request: golang/go#64728
Reviewed-on: https://go-review.googlesource.com/c/go/+/550116
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
856355a913
commit
d8311c8623
@ -192,7 +192,7 @@ func driverArgsConnLocked(ci driver.Conn, ds *driverStmt, args []any) ([]driver.
|
||||
}
|
||||
goto nextCheck
|
||||
default:
|
||||
return nil, fmt.Errorf("sql: converting argument %s type: %v", describeNamedValue(nv), err)
|
||||
return nil, fmt.Errorf("sql: converting argument %s type: %w", describeNamedValue(nv), err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,10 @@ type ValueConverter interface {
|
||||
|
||||
// Valuer is the interface providing the Value method.
|
||||
//
|
||||
// Errors returned by the [Value] method are wrapped by the database/sql package.
|
||||
// This allows callers to use [errors.Is] for precise error handling after operations
|
||||
// like [database/sql.Query], [database/sql.Exec], or [database/sql.QueryRow].
|
||||
//
|
||||
// Types implementing Valuer interface are able to convert
|
||||
// themselves to a driver [Value].
|
||||
type Valuer interface {
|
||||
|
@ -4398,6 +4398,49 @@ func TestRowsScanProperlyWrapsErrors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type alwaysErrValuer struct{}
|
||||
|
||||
// errEmpty is returned when an empty value is found
|
||||
var errEmpty = errors.New("empty value")
|
||||
|
||||
func (v alwaysErrValuer) Value() (driver.Value, error) {
|
||||
return nil, errEmpty
|
||||
}
|
||||
|
||||
// Issue 64707: Ensure that Stmt.Exec and Stmt.Query properly wraps underlying errors.
|
||||
func TestDriverArgsWrapsErrors(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
t.Run("exec", func(t *testing.T) {
|
||||
_, err := db.Exec("INSERT|keys|dec1=?", alwaysErrValuer{})
|
||||
if err == nil {
|
||||
t.Fatal("expecting back an error")
|
||||
}
|
||||
if !errors.Is(err, errEmpty) {
|
||||
t.Fatalf("errors.Is mismatch\n%v\nWant: %v", err, errEmpty)
|
||||
}
|
||||
// Ensure that error substring matching still correctly works.
|
||||
if !strings.Contains(err.Error(), errEmpty.Error()) {
|
||||
t.Fatalf("Error %v does not contain %v", err, errEmpty)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("query", func(t *testing.T) {
|
||||
_, err := db.Query("INSERT|keys|dec1=?", alwaysErrValuer{})
|
||||
if err == nil {
|
||||
t.Fatal("expecting back an error")
|
||||
}
|
||||
if !errors.Is(err, errEmpty) {
|
||||
t.Fatalf("errors.Is mismatch\n%v\nWant: %v", err, errEmpty)
|
||||
}
|
||||
// Ensure that error substring matching still correctly works.
|
||||
if !strings.Contains(err.Error(), errEmpty.Error()) {
|
||||
t.Fatalf("Error %v does not contain %v", err, errEmpty)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestContextCancelDuringRawBytesScan(t *testing.T) {
|
||||
for _, mode := range []string{"nocancel", "top", "bottom", "go"} {
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user