Allow scanning null even if PG and Go types are incompatible
refs https://github.com/jackc/pgx/issues/1326
This commit is contained in:
@@ -558,6 +558,23 @@ type scanPlanFail struct {
|
||||
}
|
||||
|
||||
func (plan *scanPlanFail) Scan(src []byte, dst any) error {
|
||||
// If src is NULL it might be possible to scan into dst even though it is the types are not compatible. While this
|
||||
// may seem to be a contrived case it can occur when selecting NULL directly. PostgreSQL assigns it the type of text.
|
||||
// It would be surprising to the caller to have to cast the NULL (e.g. `select null::int`). So try to figure out a
|
||||
// compatible data type for dst and scan with that.
|
||||
//
|
||||
// See https://github.com/jackc/pgx/issues/1326
|
||||
if src == nil {
|
||||
// As a horrible hack try all types to find anything that can scan into dst.
|
||||
for oid := range plan.m.oidToType {
|
||||
// using planScan instead of Scan or PlanScan to avoid polluting the planned scan cache.
|
||||
plan := plan.m.planScan(oid, plan.formatCode, dst)
|
||||
if _, ok := plan.(*scanPlanFail); !ok {
|
||||
return plan.Scan(src, dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var format string
|
||||
switch plan.formatCode {
|
||||
case TextFormatCode:
|
||||
|
||||
@@ -329,6 +329,21 @@ func TestMapScanPointerToRenamedType(t *testing.T) {
|
||||
assert.Equal(t, "foo", string(*rs))
|
||||
}
|
||||
|
||||
// https://github.com/jackc/pgx/issues/1326
|
||||
func TestMapScanNullToWrongType(t *testing.T) {
|
||||
m := pgtype.NewMap()
|
||||
|
||||
var n *int32
|
||||
err := m.Scan(pgtype.TextOID, pgx.TextFormatCode, nil, &n)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, n)
|
||||
|
||||
var pn pgtype.Int4
|
||||
err = m.Scan(pgtype.TextOID, pgx.TextFormatCode, nil, &pn)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, pn.Valid)
|
||||
}
|
||||
|
||||
func BenchmarkMapScanInt4IntoBinaryDecoder(b *testing.B) {
|
||||
m := pgtype.NewMap()
|
||||
src := []byte{0, 0, 0, 42}
|
||||
|
||||
Reference in New Issue
Block a user