Skip to content

Commit 84241ad

Browse files
authored
return sql.NullTime if it available (go-sql-driver#1145)
* return sql.NullTime if it available * NullTime should be used with parseTime=true option
1 parent b5b0ea5 commit 84241ad

File tree

4 files changed

+119
-115
lines changed

4 files changed

+119
-115
lines changed

driver_test.go

+108-114
Original file line numberDiff line numberDiff line change
@@ -2758,13 +2758,13 @@ func TestRowsColumnTypes(t *testing.T) {
27582758
nfNULL := sql.NullFloat64{Float64: 0.0, Valid: false}
27592759
nf0 := sql.NullFloat64{Float64: 0.0, Valid: true}
27602760
nf1337 := sql.NullFloat64{Float64: 13.37, Valid: true}
2761-
nt0 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), Valid: true}
2762-
nt1 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 100000000, time.UTC), Valid: true}
2763-
nt2 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 110000000, time.UTC), Valid: true}
2764-
nt6 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 111111000, time.UTC), Valid: true}
2765-
nd1 := NullTime{Time: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), Valid: true}
2766-
nd2 := NullTime{Time: time.Date(2006, 03, 04, 0, 0, 0, 0, time.UTC), Valid: true}
2767-
ndNULL := NullTime{Time: time.Time{}, Valid: false}
2761+
nt0 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), Valid: true}
2762+
nt1 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 100000000, time.UTC), Valid: true}
2763+
nt2 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 110000000, time.UTC), Valid: true}
2764+
nt6 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 111111000, time.UTC), Valid: true}
2765+
nd1 := nullTime{Time: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), Valid: true}
2766+
nd2 := nullTime{Time: time.Date(2006, 03, 04, 0, 0, 0, 0, time.UTC), Valid: true}
2767+
ndNULL := nullTime{Time: time.Time{}, Valid: false}
27682768
rbNULL := sql.RawBytes(nil)
27692769
rb0 := sql.RawBytes("0")
27702770
rb42 := sql.RawBytes("42")
@@ -2844,131 +2844,125 @@ func TestRowsColumnTypes(t *testing.T) {
28442844
values2 = values2[:len(values2)-2]
28452845
values3 = values3[:len(values3)-2]
28462846

2847-
dsns := []string{
2848-
dsn + "&parseTime=true",
2849-
dsn + "&parseTime=false",
2850-
}
2851-
for _, testdsn := range dsns {
2852-
runTests(t, testdsn, func(dbt *DBTest) {
2853-
dbt.mustExec("CREATE TABLE test (" + schema + ")")
2854-
dbt.mustExec("INSERT INTO test VALUES (" + values1 + "), (" + values2 + "), (" + values3 + ")")
2847+
runTests(t, dsn+"&parseTime=true", func(dbt *DBTest) {
2848+
dbt.mustExec("CREATE TABLE test (" + schema + ")")
2849+
dbt.mustExec("INSERT INTO test VALUES (" + values1 + "), (" + values2 + "), (" + values3 + ")")
28552850

2856-
rows, err := dbt.db.Query("SELECT * FROM test")
2857-
if err != nil {
2858-
t.Fatalf("Query: %v", err)
2859-
}
2851+
rows, err := dbt.db.Query("SELECT * FROM test")
2852+
if err != nil {
2853+
t.Fatalf("Query: %v", err)
2854+
}
28602855

2861-
tt, err := rows.ColumnTypes()
2862-
if err != nil {
2863-
t.Fatalf("ColumnTypes: %v", err)
2864-
}
2856+
tt, err := rows.ColumnTypes()
2857+
if err != nil {
2858+
t.Fatalf("ColumnTypes: %v", err)
2859+
}
28652860

2866-
if len(tt) != len(columns) {
2867-
t.Fatalf("unexpected number of columns: expected %d, got %d", len(columns), len(tt))
2868-
}
2861+
if len(tt) != len(columns) {
2862+
t.Fatalf("unexpected number of columns: expected %d, got %d", len(columns), len(tt))
2863+
}
28692864

2870-
types := make([]reflect.Type, len(tt))
2871-
for i, tp := range tt {
2872-
column := columns[i]
2865+
types := make([]reflect.Type, len(tt))
2866+
for i, tp := range tt {
2867+
column := columns[i]
28732868

2874-
// Name
2875-
name := tp.Name()
2876-
if name != column.name {
2877-
t.Errorf("column name mismatch %s != %s", name, column.name)
2878-
continue
2879-
}
2869+
// Name
2870+
name := tp.Name()
2871+
if name != column.name {
2872+
t.Errorf("column name mismatch %s != %s", name, column.name)
2873+
continue
2874+
}
28802875

2881-
// DatabaseTypeName
2882-
databaseTypeName := tp.DatabaseTypeName()
2883-
if databaseTypeName != column.databaseTypeName {
2884-
t.Errorf("databasetypename name mismatch for column %q: %s != %s", name, databaseTypeName, column.databaseTypeName)
2885-
continue
2886-
}
2876+
// DatabaseTypeName
2877+
databaseTypeName := tp.DatabaseTypeName()
2878+
if databaseTypeName != column.databaseTypeName {
2879+
t.Errorf("databasetypename name mismatch for column %q: %s != %s", name, databaseTypeName, column.databaseTypeName)
2880+
continue
2881+
}
28872882

2888-
// ScanType
2889-
scanType := tp.ScanType()
2890-
if scanType != column.scanType {
2891-
if scanType == nil {
2892-
t.Errorf("scantype is null for column %q", name)
2893-
} else {
2894-
t.Errorf("scantype mismatch for column %q: %s != %s", name, scanType.Name(), column.scanType.Name())
2895-
}
2896-
continue
2883+
// ScanType
2884+
scanType := tp.ScanType()
2885+
if scanType != column.scanType {
2886+
if scanType == nil {
2887+
t.Errorf("scantype is null for column %q", name)
2888+
} else {
2889+
t.Errorf("scantype mismatch for column %q: %s != %s", name, scanType.Name(), column.scanType.Name())
28972890
}
2898-
types[i] = scanType
2899-
2900-
// Nullable
2901-
nullable, ok := tp.Nullable()
2891+
continue
2892+
}
2893+
types[i] = scanType
2894+
2895+
// Nullable
2896+
nullable, ok := tp.Nullable()
2897+
if !ok {
2898+
t.Errorf("nullable not ok %q", name)
2899+
continue
2900+
}
2901+
if nullable != column.nullable {
2902+
t.Errorf("nullable mismatch for column %q: %t != %t", name, nullable, column.nullable)
2903+
}
2904+
2905+
// Length
2906+
// length, ok := tp.Length()
2907+
// if length != column.length {
2908+
// if !ok {
2909+
// t.Errorf("length not ok for column %q", name)
2910+
// } else {
2911+
// t.Errorf("length mismatch for column %q: %d != %d", name, length, column.length)
2912+
// }
2913+
// continue
2914+
// }
2915+
2916+
// Precision and Scale
2917+
precision, scale, ok := tp.DecimalSize()
2918+
if precision != column.precision {
29022919
if !ok {
2903-
t.Errorf("nullable not ok %q", name)
2904-
continue
2905-
}
2906-
if nullable != column.nullable {
2907-
t.Errorf("nullable mismatch for column %q: %t != %t", name, nullable, column.nullable)
2920+
t.Errorf("precision not ok for column %q", name)
2921+
} else {
2922+
t.Errorf("precision mismatch for column %q: %d != %d", name, precision, column.precision)
29082923
}
2909-
2910-
// Length
2911-
// length, ok := tp.Length()
2912-
// if length != column.length {
2913-
// if !ok {
2914-
// t.Errorf("length not ok for column %q", name)
2915-
// } else {
2916-
// t.Errorf("length mismatch for column %q: %d != %d", name, length, column.length)
2917-
// }
2918-
// continue
2919-
// }
2920-
2921-
// Precision and Scale
2922-
precision, scale, ok := tp.DecimalSize()
2923-
if precision != column.precision {
2924-
if !ok {
2925-
t.Errorf("precision not ok for column %q", name)
2926-
} else {
2927-
t.Errorf("precision mismatch for column %q: %d != %d", name, precision, column.precision)
2928-
}
2929-
continue
2930-
}
2931-
if scale != column.scale {
2932-
if !ok {
2933-
t.Errorf("scale not ok for column %q", name)
2934-
} else {
2935-
t.Errorf("scale mismatch for column %q: %d != %d", name, scale, column.scale)
2936-
}
2937-
continue
2924+
continue
2925+
}
2926+
if scale != column.scale {
2927+
if !ok {
2928+
t.Errorf("scale not ok for column %q", name)
2929+
} else {
2930+
t.Errorf("scale mismatch for column %q: %d != %d", name, scale, column.scale)
29382931
}
2932+
continue
29392933
}
2934+
}
29402935

2941-
values := make([]interface{}, len(tt))
2942-
for i := range values {
2943-
values[i] = reflect.New(types[i]).Interface()
2936+
values := make([]interface{}, len(tt))
2937+
for i := range values {
2938+
values[i] = reflect.New(types[i]).Interface()
2939+
}
2940+
i := 0
2941+
for rows.Next() {
2942+
err = rows.Scan(values...)
2943+
if err != nil {
2944+
t.Fatalf("failed to scan values in %v", err)
29442945
}
2945-
i := 0
2946-
for rows.Next() {
2947-
err = rows.Scan(values...)
2948-
if err != nil {
2949-
t.Fatalf("failed to scan values in %v", err)
2950-
}
2951-
for j := range values {
2952-
value := reflect.ValueOf(values[j]).Elem().Interface()
2953-
if !reflect.DeepEqual(value, columns[j].valuesOut[i]) {
2954-
if columns[j].scanType == scanTypeRawBytes {
2955-
t.Errorf("row %d, column %d: %v != %v", i, j, string(value.(sql.RawBytes)), string(columns[j].valuesOut[i].(sql.RawBytes)))
2956-
} else {
2957-
t.Errorf("row %d, column %d: %v != %v", i, j, value, columns[j].valuesOut[i])
2958-
}
2946+
for j := range values {
2947+
value := reflect.ValueOf(values[j]).Elem().Interface()
2948+
if !reflect.DeepEqual(value, columns[j].valuesOut[i]) {
2949+
if columns[j].scanType == scanTypeRawBytes {
2950+
t.Errorf("row %d, column %d: %v != %v", i, j, string(value.(sql.RawBytes)), string(columns[j].valuesOut[i].(sql.RawBytes)))
2951+
} else {
2952+
t.Errorf("row %d, column %d: %v != %v", i, j, value, columns[j].valuesOut[i])
29592953
}
29602954
}
2961-
i++
2962-
}
2963-
if i != 3 {
2964-
t.Errorf("expected 3 rows, got %d", i)
29652955
}
2956+
i++
2957+
}
2958+
if i != 3 {
2959+
t.Errorf("expected 3 rows, got %d", i)
2960+
}
29662961

2967-
if err := rows.Close(); err != nil {
2968-
t.Errorf("error closing rows: %s", err)
2969-
}
2970-
})
2971-
}
2962+
if err := rows.Close(); err != nil {
2963+
t.Errorf("error closing rows: %s", err)
2964+
}
2965+
})
29722966
}
29732967

29742968
func TestValuerWithValueReceiverGivenNilValue(t *testing.T) {

fields.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ var (
106106
scanTypeInt64 = reflect.TypeOf(int64(0))
107107
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
108108
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
109-
scanTypeNullTime = reflect.TypeOf(NullTime{})
109+
scanTypeNullTime = reflect.TypeOf(nullTime{})
110110
scanTypeUint8 = reflect.TypeOf(uint8(0))
111111
scanTypeUint16 = reflect.TypeOf(uint16(0))
112112
scanTypeUint32 = reflect.TypeOf(uint32(0))

nulltime_go113.go

+5
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ import (
3333
// NullTime.Scan interprets a time as UTC, not the loc DSN parameter.
3434
// Use sql.NullTime instead.
3535
type NullTime sql.NullTime
36+
37+
// for internal use.
38+
// the mysql package uses sql.NullTime if it is available.
39+
// if not, the package uses mysql.NullTime.
40+
type nullTime = sql.NullTime // sql.NullTime is available

nulltime_legacy.go

+5
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,8 @@ type NullTime struct {
3232
Time time.Time
3333
Valid bool // Valid is true if Time is not NULL
3434
}
35+
36+
// for internal use.
37+
// the mysql package uses sql.NullTime if it is available.
38+
// if not, the package uses mysql.NullTime.
39+
type nullTime = NullTime // sql.NullTime is not available

0 commit comments

Comments
 (0)