Skip to content

Commit 0bc29e3

Browse files
authored
Merge pull request #2225 from logicbomb/improve-error-message
Include the field name in error messages when scanning structs
2 parents 9cce059 + 9c0ad69 commit 0bc29e3

File tree

6 files changed

+26
-10
lines changed

6 files changed

+26
-10
lines changed

pgtype/json_test.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"database/sql/driver"
77
"encoding/json"
88
"errors"
9+
"fmt"
910
"reflect"
1011
"testing"
1112

@@ -191,11 +192,15 @@ func TestJSONCodecUnmarshalSQLNull(t *testing.T) {
191192
// A string cannot scan a NULL.
192193
str := "foobar"
193194
err = conn.QueryRow(ctx, "select null::json").Scan(&str)
194-
require.EqualError(t, err, "can't scan into dest[0]: cannot scan NULL into *string")
195+
fieldName := "json"
196+
if conn.PgConn().ParameterStatus("crdb_version") != "" {
197+
fieldName = "jsonb" // Seems like CockroachDB treats json as jsonb.
198+
}
199+
require.EqualError(t, err, fmt.Sprintf("can't scan into dest[0] (col: %s): cannot scan NULL into *string", fieldName))
195200

196201
// A non-string cannot scan a NULL.
197202
err = conn.QueryRow(ctx, "select null::json").Scan(&n)
198-
require.EqualError(t, err, "can't scan into dest[0]: cannot scan NULL into *int")
203+
require.EqualError(t, err, fmt.Sprintf("can't scan into dest[0] (col: %s): cannot scan NULL into *int", fieldName))
199204
})
200205
}
201206

pgtype/jsonb_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ func TestJSONBCodecUnmarshalSQLNull(t *testing.T) {
6666
// A string cannot scan a NULL.
6767
str := "foobar"
6868
err = conn.QueryRow(ctx, "select null::jsonb").Scan(&str)
69-
require.EqualError(t, err, "can't scan into dest[0]: cannot scan NULL into *string")
69+
require.EqualError(t, err, "can't scan into dest[0] (col: jsonb): cannot scan NULL into *string")
7070

7171
// A non-string cannot scan a NULL.
7272
err = conn.QueryRow(ctx, "select null::jsonb").Scan(&n)
73-
require.EqualError(t, err, "can't scan into dest[0]: cannot scan NULL into *int")
73+
require.EqualError(t, err, "can't scan into dest[0] (col: jsonb): cannot scan NULL into *int")
7474
})
7575
}
7676

pgtype/xml_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func TestXMLCodecUnmarshalSQLNull(t *testing.T) {
7979
// A string cannot scan a NULL.
8080
str := "foobar"
8181
err = conn.QueryRow(ctx, "select null::xml").Scan(&str)
82-
assert.EqualError(t, err, "can't scan into dest[0]: cannot scan NULL into *string")
82+
assert.EqualError(t, err, "can't scan into dest[0] (col: xml): cannot scan NULL into *string")
8383
})
8484
}
8585

query_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ func TestConnQueryReadWrongTypeError(t *testing.T) {
420420
t.Fatal("Expected Rows to have an error after an improper read but it didn't")
421421
}
422422

423-
if rows.Err().Error() != "can't scan into dest[0]: cannot scan int4 (OID 23) in binary format into *time.Time" {
423+
if rows.Err().Error() != "can't scan into dest[0] (col: n): cannot scan int4 (OID 23) in binary format into *time.Time" {
424424
t.Fatalf("Expected different Rows.Err(): %v", rows.Err())
425425
}
426426

rows.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ func (rows *baseRows) Scan(dest ...any) error {
272272

273273
err := rows.scanPlans[i].Scan(values[i], dst)
274274
if err != nil {
275-
err = ScanArgError{ColumnIndex: i, Err: err}
275+
err = ScanArgError{ColumnIndex: i, FieldName: fieldDescriptions[i].Name, Err: err}
276276
rows.fatal(err)
277277
return err
278278
}
@@ -334,11 +334,16 @@ func (rows *baseRows) Conn() *Conn {
334334

335335
type ScanArgError struct {
336336
ColumnIndex int
337+
FieldName string
337338
Err error
338339
}
339340

340341
func (e ScanArgError) Error() string {
341-
return fmt.Sprintf("can't scan into dest[%d]: %v", e.ColumnIndex, e.Err)
342+
if e.FieldName == "?column?" { // Don't include the fieldname if it's unknown
343+
return fmt.Sprintf("can't scan into dest[%d]: %v", e.ColumnIndex, e.Err)
344+
}
345+
346+
return fmt.Sprintf("can't scan into dest[%d] (col: %s): %v", e.ColumnIndex, e.FieldName, e.Err)
342347
}
343348

344349
func (e ScanArgError) Unwrap() error {
@@ -366,7 +371,7 @@ func ScanRow(typeMap *pgtype.Map, fieldDescriptions []pgconn.FieldDescription, v
366371

367372
err := typeMap.Scan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], d)
368373
if err != nil {
369-
return ScanArgError{ColumnIndex: i, Err: err}
374+
return ScanArgError{ColumnIndex: i, FieldName: fieldDescriptions[i].Name, Err: err}
370375
}
371376
}
372377

values_test.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package pgx_test
33
import (
44
"bytes"
55
"context"
6+
"fmt"
67
"net"
78
"os"
89
"reflect"
@@ -215,7 +216,12 @@ func testJSONInt16ArrayFailureDueToOverflow(t *testing.T, conn *pgx.Conn, typena
215216
input := []int{1, 2, 234432}
216217
var output []int16
217218
err := conn.QueryRow(context.Background(), "select $1::"+typename, input).Scan(&output)
218-
if err == nil || err.Error() != "can't scan into dest[0]: json: cannot unmarshal number 234432 into Go value of type int16" {
219+
fieldName := typename
220+
if conn.PgConn().ParameterStatus("crdb_version") != "" && typename == "json" {
221+
fieldName = "jsonb" // Seems like CockroachDB treats json as jsonb.
222+
}
223+
expectedMessage := fmt.Sprintf("can't scan into dest[0] (col: %s): json: cannot unmarshal number 234432 into Go value of type int16", fieldName)
224+
if err == nil || err.Error() != expectedMessage {
219225
t.Errorf("%s: Expected *json.UnmarshalTypeError, but got %v", typename, err)
220226
}
221227
}

0 commit comments

Comments
 (0)