From 8da7706bb4dc609689fd69e196ddaa800908c31f Mon Sep 17 00:00:00 2001 From: HaraldNordgren Date: Sun, 7 Jan 2018 15:08:59 +0100 Subject: [PATCH] database/sql: include SQL column name in Scan() error message When 'convertAssign' gives an error, instead of giving just the index of the failing column -- which is not always helpful, especially when there are lots of columns in the query -- utilize 'rs.rowsi.Columns()' to extract the underlying column name and include that in the error string: sql: Scan error on column index 0, name "some_column": ... Fixes #23362 Change-Id: I0fe71ff3c25f4c0dd9fc6aa2c2da2360dd93e3e0 Reviewed-on: https://go-review.googlesource.com/86537 Reviewed-by: Harald Nordgren Reviewed-by: Daniel Theophanes Run-TryBot: Daniel Theophanes TryBot-Result: Gobot Gobot --- src/database/sql/sql.go | 2 +- src/database/sql/sql_test.go | 53 +++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 8f5588ed26..a6fa153d94 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -2885,7 +2885,7 @@ func (rs *Rows) Scan(dest ...interface{}) error { for i, sv := range rs.lastcols { err := convertAssign(dest[i], sv) if err != nil { - return fmt.Errorf("sql: Scan error on column index %d: %v", i, err) + return fmt.Errorf(`sql: Scan error on column index %d, name %q: %v`, i, rs.rowsi.Columns()[i], err) } } return nil diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index ae6bf7102e..405e818185 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -1338,6 +1338,57 @@ func TestConnQuery(t *testing.T) { } } +func TestInvalidNilValues(t *testing.T) { + var date1 time.Time + var date2 int + + tests := []struct { + name string + input interface{} + expectedError string + }{ + { + name: "time.Time", + input: &date1, + expectedError: `sql: Scan error on column index 0, name "bdate": unsupported Scan, storing driver.Value type into type *time.Time`, + }, + { + name: "int", + input: &date2, + expectedError: `sql: Scan error on column index 0, name "bdate": converting driver.Value type ("") to a int: invalid syntax`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + conn, err := db.Conn(ctx) + if err != nil { + t.Fatal(err) + } + conn.dc.ci.(*fakeConn).skipDirtySession = true + defer conn.Close() + + err = conn.QueryRowContext(ctx, "SELECT|people|bdate|age=?", 1).Scan(tt.input) + if err == nil { + t.Fatal("expected error when querying nil column, but suceeded") + } + if err.Error() != tt.expectedError { + t.Fatalf("Expected error: %s\nReceived: %s", tt.expectedError, err.Error()) + } + + err = conn.PingContext(ctx) + if err != nil { + t.Fatal(err) + } + }) + } +} + func TestConnTx(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -1659,7 +1710,7 @@ func TestQueryRowNilScanDest(t *testing.T) { 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" + want := `sql: Scan error on column index 0, name "name": destination pointer is nil` if err == nil || err.Error() != want { t.Errorf("error = %q; want %q", err.Error(), want) }