"strconv"
)
+var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+
// driverArgs converts arguments from callers of Stmt.Exec and
// Stmt.Query into driver Values.
//
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type.
func convertAssign(dest, src interface{}) error {
- // Common cases, without reflect. Fall through.
+ // Common cases, without reflect.
switch s := src.(type) {
case string:
switch d := dest.(type) {
case *string:
+ if d == nil {
+ return errNilPtr
+ }
*d = s
return nil
case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
*d = []byte(s)
return nil
}
case []byte:
switch d := dest.(type) {
case *string:
+ if d == nil {
+ return errNilPtr
+ }
*d = string(s)
return nil
case *interface{}:
+ if d == nil {
+ return errNilPtr
+ }
bcopy := make([]byte, len(s))
copy(bcopy, s)
*d = bcopy
return nil
case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
*d = s
return nil
}
case nil:
switch d := dest.(type) {
case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
*d = nil
return nil
}
if dpv.Kind() != reflect.Ptr {
return errors.New("destination not a pointer")
}
+ if dpv.IsNil() {
+ return errNilPtr
+ }
if !sv.IsValid() {
sv = reflect.ValueOf(src)
}
}
}
+
+// golang.org/issue/4859
+func TestQueryRowNilScanDest(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ var name *string // nil pointer
+ err := db.QueryRow("SELECT|people|name|").Scan(name)
+ want := "sql: Scan error on column index 0: destination pointer is nil"
+ if err == nil || err.Error() != want {
+ t.Errorf("error = %q; want %q", err.Error(), want)
+ }
+}