2
0

Allow scanning null even if PG and Go types are incompatible

refs https://github.com/jackc/pgx/issues/1326
This commit is contained in:
Jack Christensen
2022-10-08 09:10:43 -05:00
parent 5655f9d593
commit af0b896290
2 changed files with 32 additions and 0 deletions
+17
View File
@@ -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:
+15
View File
@@ -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}