Commit 325c2aa5 authored by Daniel Theophanes's avatar Daniel Theophanes Committed by Brad Fitzpatrick

database/sql: update the conversion errors to be clearer

There was some ambiguity over which argument was referred to when
a conversion error was returned. Now refer to the argument by
either explicit ordinal position or name if present.

Fixes #15676

Change-Id: Id933196b7e648baa664f4121fa3fb1b07b3c4880
Reviewed-on: https://go-review.googlesource.com/31262Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 930ab0af
...@@ -17,6 +17,13 @@ import ( ...@@ -17,6 +17,13 @@ import (
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
func describeNamedValue(nv *driver.NamedValue) string {
if len(nv.Name) == 0 {
return fmt.Sprintf("$%d", nv.Ordinal)
}
return fmt.Sprintf("with name %q", nv.Name)
}
// driverArgs converts arguments from callers of Stmt.Exec and // driverArgs converts arguments from callers of Stmt.Exec and
// Stmt.Query into driver Values. // Stmt.Query into driver Values.
// //
...@@ -33,15 +40,16 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) ...@@ -33,15 +40,16 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error)
if !ok { if !ok {
for n, arg := range args { for n, arg := range args {
var err error var err error
nvargs[n].Ordinal = n + 1 nv := &nvargs[n]
nv.Ordinal = n + 1
if np, ok := arg.(NamedParam); ok { if np, ok := arg.(NamedParam); ok {
arg = np.Value arg = np.Value
nvargs[n].Name = np.Name nvargs[n].Name = np.Name
} }
nvargs[n].Value, err = driver.DefaultParameterConverter.ConvertValue(arg) nv.Value, err = driver.DefaultParameterConverter.ConvertValue(arg)
if err != nil { if err != nil {
return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) return nil, fmt.Errorf("sql: converting Exec argument %s type: %v", describeNamedValue(nv), err)
} }
} }
return nvargs, nil return nvargs, nil
...@@ -49,10 +57,11 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) ...@@ -49,10 +57,11 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error)
// Let the Stmt convert its own arguments. // Let the Stmt convert its own arguments.
for n, arg := range args { for n, arg := range args {
nvargs[n].Ordinal = n + 1 nv := &nvargs[n]
nv.Ordinal = n + 1
if np, ok := arg.(NamedParam); ok { if np, ok := arg.(NamedParam); ok {
arg = np.Value arg = np.Value
nvargs[n].Name = np.Name nv.Name = np.Name
} }
// First, see if the value itself knows how to convert // First, see if the value itself knows how to convert
// itself to a driver type. For example, a NullString // itself to a driver type. For example, a NullString
...@@ -60,10 +69,10 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) ...@@ -60,10 +69,10 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error)
if vr, ok := arg.(driver.Valuer); ok { if vr, ok := arg.(driver.Valuer); ok {
sv, err := callValuerValue(vr) sv, err := callValuerValue(vr)
if err != nil { if err != nil {
return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err) return nil, fmt.Errorf("sql: argument %s from Value: %v", describeNamedValue(nv), err)
} }
if !driver.IsValue(sv) { if !driver.IsValue(sv) {
return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv) return nil, fmt.Errorf("sql: argument %s: non-subset type %T returned from Value", describeNamedValue(nv), sv)
} }
arg = sv arg = sv
} }
...@@ -77,14 +86,14 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) ...@@ -77,14 +86,14 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error)
// same error. // same error.
var err error var err error
ds.Lock() ds.Lock()
nvargs[n].Value, err = cc.ColumnConverter(n).ConvertValue(arg) nv.Value, err = cc.ColumnConverter(n).ConvertValue(arg)
ds.Unlock() ds.Unlock()
if err != nil { if err != nil {
return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err) return nil, fmt.Errorf("sql: converting argument %s type: %v", describeNamedValue(nv), err)
} }
if !driver.IsValue(nvargs[n].Value) { if !driver.IsValue(nv.Value) {
return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T", return nil, fmt.Errorf("sql: for argument %s, driver ColumnConverter error converted %T to unsupported type %T",
arg, nvargs[n].Value) describeNamedValue(nv), arg, nv.Value)
} }
} }
......
...@@ -745,8 +745,8 @@ func TestExec(t *testing.T) { ...@@ -745,8 +745,8 @@ func TestExec(t *testing.T) {
{[]interface{}{7, 9}, ""}, {[]interface{}{7, 9}, ""},
// Invalid conversions: // Invalid conversions:
{[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument #1's type: sql/driver: value 4294967295 overflows int32"}, {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument $2 type: sql/driver: value 4294967295 overflows int32"},
{[]interface{}{"Brad", "strconv fail"}, "sql: converting argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"}, {[]interface{}{"Brad", "strconv fail"}, `sql: converting argument $2 type: sql/driver: value "strconv fail" can't be converted to int32`},
// Wrong number of args: // Wrong number of args:
{[]interface{}{}, "sql: expected 2 arguments, got 0"}, {[]interface{}{}, "sql: expected 2 arguments, got 0"},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment