Rows.Scan errors now include which argument caused error

pull/109/head
Jack Christensen 2015-11-20 14:02:49 -06:00
parent dd26ad0091
commit edfdaf15c6
4 changed files with 23 additions and 7 deletions

View File

@ -1,3 +1,7 @@
# Tip
* Rows.Scan errors now include which argument caused error
# 2.7.1 (October 26, 2015)
* Disable SSL renegotiation

View File

@ -214,6 +214,15 @@ func (rows *Rows) nextColumn() (*ValueReader, bool) {
return &rows.vr, true
}
type scanArgError struct {
col int
err error
}
func (e scanArgError) Error() string {
return fmt.Sprintf("can't scan into dest[%d]: %v", e.col, e.err)
}
// Scan reads the values from the current row into dest values positionally.
// dest can include pointers to core types, values implementing the Scanner
// interface, and []byte. []byte will skip the decoding process and directly
@ -225,7 +234,7 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
return err
}
for _, d := range dest {
for i, d := range dest {
vr, _ := rows.nextColumn()
// Check for []byte first as we allow sidestepping the decoding process and retrieving the raw bytes
@ -244,7 +253,7 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
} else if s, ok := d.(Scanner); ok {
err = s.Scan(vr)
if err != nil {
rows.Fatal(err)
rows.Fatal(scanArgError{col: i, err: err})
}
} else if vr.Type().DataType == JsonOid || vr.Type().DataType == JsonbOid {
decodeJson(vr, &d)
@ -292,7 +301,7 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
case TimestampOid:
*v = decodeTimestamp(vr)
default:
rows.Fatal(fmt.Errorf("Can't convert OID %v to time.Time", vr.Type().DataType))
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("Can't convert OID %v to time.Time", vr.Type().DataType)})
}
case *net.IPNet:
*v = decodeInet(vr)
@ -319,12 +328,12 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
}
}
}
rows.Fatal(fmt.Errorf("Scan cannot decode into %T", d))
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("Scan cannot decode into %T", d)})
}
}
if vr.Err() != nil {
rows.Fatal(vr.Err())
rows.Fatal(scanArgError{col: i, err: vr.Err()})
}
if rows.Err() != nil {

View File

@ -161,6 +161,10 @@ func TestConnQueryReadWrongTypeError(t *testing.T) {
t.Fatal("Expected Rows to have an error after an improper read but it didn't")
}
if rows.Err().Error() != "can't scan into dest[0]: Can't convert OID 23 to time.Time" {
t.Fatalf("Expected different Rows.Err(): %v", rows.Err())
}
ensureConnValid(t, conn)
}

View File

@ -1,7 +1,6 @@
package pgx_test
import (
"encoding/json"
"github.com/jackc/pgx"
"net"
"reflect"
@ -196,7 +195,7 @@ func testJsonInt16ArrayFailureDueToOverflow(t *testing.T, conn *pgx.Conn, typena
input := []int{1, 2, 234432}
var output []int16
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if _, ok := err.(*json.UnmarshalTypeError); !ok {
if err.Error() != "can't scan into dest[0]: json: cannot unmarshal number 234432 into Go value of type int16" {
t.Errorf("%s: Expected *json.UnmarkalTypeError, but got %v", typename, err)
}
}