Improve unknown type support for database/sql

- Return unknown type OID instead of empty string for type name.
- ScanType is string instead of empty interface for unknown types.

fixes #759
pull/768/head
Jack Christensen 2020-05-30 13:25:30 -05:00
parent 837704dc7d
commit 8dee3382f7
2 changed files with 26 additions and 9 deletions

View File

@ -56,6 +56,7 @@ import (
"io" "io"
"math" "math"
"reflect" "reflect"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -423,13 +424,13 @@ func (r *Rows) Columns() []string {
return names return names
} }
// ColumnTypeDatabaseTypeName return the database system type name. // ColumnTypeDatabaseTypeName returns the database system type name. If the name is unknown the OID is returned.
func (r *Rows) ColumnTypeDatabaseTypeName(index int) string { func (r *Rows) ColumnTypeDatabaseTypeName(index int) string {
if dt, ok := r.conn.conn.ConnInfo().DataTypeForOID(r.rows.FieldDescriptions()[index].DataTypeOID); ok { if dt, ok := r.conn.conn.ConnInfo().DataTypeForOID(r.rows.FieldDescriptions()[index].DataTypeOID); ok {
return strings.ToUpper(dt.Name) return strings.ToUpper(dt.Name)
} }
return "" return strconv.FormatInt(int64(r.rows.FieldDescriptions()[index].DataTypeOID), 10)
} }
const varHeaderSize = 4 const varHeaderSize = 4
@ -481,8 +482,6 @@ func (r *Rows) ColumnTypeScanType(index int) reflect.Type {
return reflect.TypeOf(int32(0)) return reflect.TypeOf(int32(0))
case pgtype.Int2OID: case pgtype.Int2OID:
return reflect.TypeOf(int16(0)) return reflect.TypeOf(int16(0))
case pgtype.VarcharOID, pgtype.BPCharArrayOID, pgtype.TextOID:
return reflect.TypeOf("")
case pgtype.BoolOID: case pgtype.BoolOID:
return reflect.TypeOf(false) return reflect.TypeOf(false)
case pgtype.NumericOID: case pgtype.NumericOID:
@ -492,7 +491,7 @@ func (r *Rows) ColumnTypeScanType(index int) reflect.Type {
case pgtype.ByteaOID: case pgtype.ByteaOID:
return reflect.TypeOf([]byte(nil)) return reflect.TypeOf([]byte(nil))
default: default:
return reflect.TypeOf(new(interface{})).Elem() return reflect.TypeOf("")
} }
} }

View File

@ -834,17 +834,35 @@ func TestRowsColumnTypes(t *testing.T) {
OK: true, OK: true,
}, },
ScanType: reflect.TypeOf(float64(0)), ScanType: reflect.TypeOf(float64(0)),
}, {
Name: "d",
TypeName: "1266",
Length: struct {
Len int64
OK bool
}{
Len: 0,
OK: false,
},
DecimalSize: struct {
Precision int64
Scale int64
OK bool
}{
Precision: 0,
Scale: 0,
OK: false,
},
ScanType: reflect.TypeOf(""),
}, },
} }
rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar, 1.28::numeric(9, 2) AS dec") rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar, 1.28::numeric(9, 2) AS dec, '12:00:00'::timetz as d")
require.NoError(t, err) require.NoError(t, err)
columns, err := rows.ColumnTypes() columns, err := rows.ColumnTypes()
require.NoError(t, err) require.NoError(t, err)
if len(columns) != 3 { assert.Len(t, columns, 4)
t.Errorf("expected 3 columns found %d", len(columns))
}
for i, tt := range columnTypesTests { for i, tt := range columnTypesTests {
c := columns[i] c := columns[i]