database/sql: check for nil Scan pointers

Return nice errors and don't panic.

Fixes #4859

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7383046
diff --git a/src/pkg/database/sql/convert.go b/src/pkg/database/sql/convert.go
index 964dc18..853a782 100644
--- a/src/pkg/database/sql/convert.go
+++ b/src/pkg/database/sql/convert.go
@@ -14,6 +14,8 @@
 	"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.
 //
@@ -75,34 +77,52 @@
 // 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
 		}
@@ -140,6 +160,9 @@
 	if dpv.Kind() != reflect.Ptr {
 		return errors.New("destination not a pointer")
 	}
+	if dpv.IsNil() {
+		return errNilPtr
+	}
 
 	if !sv.IsValid() {
 		sv = reflect.ValueOf(src)
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
index 74ba8e0..53b2296 100644
--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -696,3 +696,15 @@
 		}
 	}
 }
+
+// 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)
+	}
+}