mirror of
https://github.com/golang/go
synced 2024-11-25 10:07:56 -07:00
exp/sql: add time.Time support
Fixes #2694 R=golang-dev, r CC=golang-dev https://golang.org/cl/5541057
This commit is contained in:
parent
a08c1960dd
commit
bf734d62d8
@ -8,8 +8,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var someTime = time.Unix(123, 0)
|
||||||
|
|
||||||
type conversionTest struct {
|
type conversionTest struct {
|
||||||
s, d interface{} // source and destination
|
s, d interface{} // source and destination
|
||||||
|
|
||||||
@ -19,6 +22,7 @@ type conversionTest struct {
|
|||||||
wantstr string
|
wantstr string
|
||||||
wantf32 float32
|
wantf32 float32
|
||||||
wantf64 float64
|
wantf64 float64
|
||||||
|
wanttime time.Time
|
||||||
wantbool bool // used if d is of type *bool
|
wantbool bool // used if d is of type *bool
|
||||||
wanterr string
|
wanterr string
|
||||||
}
|
}
|
||||||
@ -35,12 +39,14 @@ var (
|
|||||||
scanbool bool
|
scanbool bool
|
||||||
scanf32 float32
|
scanf32 float32
|
||||||
scanf64 float64
|
scanf64 float64
|
||||||
|
scantime time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
var conversionTests = []conversionTest{
|
var conversionTests = []conversionTest{
|
||||||
// Exact conversions (destination pointer type matches source type)
|
// Exact conversions (destination pointer type matches source type)
|
||||||
{s: "foo", d: &scanstr, wantstr: "foo"},
|
{s: "foo", d: &scanstr, wantstr: "foo"},
|
||||||
{s: 123, d: &scanint, wantint: 123},
|
{s: 123, d: &scanint, wantint: 123},
|
||||||
|
{s: someTime, d: &scantime, wanttime: someTime},
|
||||||
|
|
||||||
// To strings
|
// To strings
|
||||||
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
|
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
|
||||||
@ -106,6 +112,10 @@ func float32Value(ptr interface{}) float32 {
|
|||||||
return *(ptr.(*float32))
|
return *(ptr.(*float32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timeValue(ptr interface{}) time.Time {
|
||||||
|
return *(ptr.(*time.Time))
|
||||||
|
}
|
||||||
|
|
||||||
func TestConversions(t *testing.T) {
|
func TestConversions(t *testing.T) {
|
||||||
for n, ct := range conversionTests {
|
for n, ct := range conversionTests {
|
||||||
err := convertAssign(ct.d, ct.s)
|
err := convertAssign(ct.d, ct.s)
|
||||||
@ -138,6 +148,9 @@ func TestConversions(t *testing.T) {
|
|||||||
if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" {
|
if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" {
|
||||||
errf("want bool %v, got %v", ct.wantbool, *bp)
|
errf("want bool %v, got %v", ct.wantbool, *bp)
|
||||||
}
|
}
|
||||||
|
if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) {
|
||||||
|
errf("want time %v, got %v", ct.wanttime, timeValue(ct.d))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
// nil
|
// nil
|
||||||
// []byte
|
// []byte
|
||||||
// string [*] everywhere except from Rows.Next.
|
// string [*] everywhere except from Rows.Next.
|
||||||
|
// time.Time
|
||||||
//
|
//
|
||||||
package driver
|
package driver
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValueConverter is the interface providing the ConvertValue method.
|
// ValueConverter is the interface providing the ConvertValue method.
|
||||||
@ -143,9 +144,10 @@ func (stringType) ConvertValue(v interface{}) (interface{}, error) {
|
|||||||
// bool
|
// bool
|
||||||
// nil
|
// nil
|
||||||
// []byte
|
// []byte
|
||||||
|
// time.Time
|
||||||
// string
|
// string
|
||||||
//
|
//
|
||||||
// This is the ame list as IsScanSubsetType, with the addition of
|
// This is the same list as IsScanSubsetType, with the addition of
|
||||||
// string.
|
// string.
|
||||||
func IsParameterSubsetType(v interface{}) bool {
|
func IsParameterSubsetType(v interface{}) bool {
|
||||||
if IsScanSubsetType(v) {
|
if IsScanSubsetType(v) {
|
||||||
@ -165,6 +167,7 @@ func IsParameterSubsetType(v interface{}) bool {
|
|||||||
// bool
|
// bool
|
||||||
// nil
|
// nil
|
||||||
// []byte
|
// []byte
|
||||||
|
// time.Time
|
||||||
//
|
//
|
||||||
// This is the same list as IsParameterSubsetType, without string.
|
// This is the same list as IsParameterSubsetType, without string.
|
||||||
func IsScanSubsetType(v interface{}) bool {
|
func IsScanSubsetType(v interface{}) bool {
|
||||||
@ -172,7 +175,7 @@ func IsScanSubsetType(v interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
case int64, float64, []byte, bool:
|
case int64, float64, []byte, bool, time.Time:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -7,6 +7,7 @@ package driver
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type valueConverterTest struct {
|
type valueConverterTest struct {
|
||||||
@ -16,6 +17,8 @@ type valueConverterTest struct {
|
|||||||
err string
|
err string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var now = time.Now()
|
||||||
|
|
||||||
var valueConverterTests = []valueConverterTest{
|
var valueConverterTests = []valueConverterTest{
|
||||||
{Bool, "true", true, ""},
|
{Bool, "true", true, ""},
|
||||||
{Bool, "True", true, ""},
|
{Bool, "True", true, ""},
|
||||||
@ -33,6 +36,7 @@ var valueConverterTests = []valueConverterTest{
|
|||||||
{Bool, uint16(0), false, ""},
|
{Bool, uint16(0), false, ""},
|
||||||
{c: Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"},
|
{c: Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"},
|
||||||
{c: Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"},
|
{c: Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"},
|
||||||
|
{DefaultParameterConverter, now, now, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValueConverters(t *testing.T) {
|
func TestValueConverters(t *testing.T) {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"exp/sql/driver"
|
"exp/sql/driver"
|
||||||
)
|
)
|
||||||
@ -220,7 +221,7 @@ func (c *fakeConn) Close() error {
|
|||||||
func checkSubsetTypes(args []interface{}) error {
|
func checkSubsetTypes(args []interface{}) error {
|
||||||
for n, arg := range args {
|
for n, arg := range args {
|
||||||
switch arg.(type) {
|
switch arg.(type) {
|
||||||
case int64, float64, bool, nil, []byte, string:
|
case int64, float64, bool, nil, []byte, string, time.Time:
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
|
return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
|
||||||
}
|
}
|
||||||
@ -589,6 +590,8 @@ func converterForType(typ string) driver.ValueConverter {
|
|||||||
return driver.Int32
|
return driver.Int32
|
||||||
case "string":
|
case "string":
|
||||||
return driver.String
|
return driver.String
|
||||||
|
case "datetime":
|
||||||
|
return driver.DefaultParameterConverter
|
||||||
}
|
}
|
||||||
panic("invalid fakedb column type of " + typ)
|
panic("invalid fakedb column type of " + typ)
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,13 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const fakeDBName = "foo"
|
const fakeDBName = "foo"
|
||||||
|
|
||||||
|
var chrisBirthday = time.Unix(123456789, 0)
|
||||||
|
|
||||||
func newTestDB(t *testing.T, name string) *DB {
|
func newTestDB(t *testing.T, name string) *DB {
|
||||||
db, err := Open("test", fakeDBName)
|
db, err := Open("test", fakeDBName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -21,10 +24,10 @@ func newTestDB(t *testing.T, name string) *DB {
|
|||||||
t.Fatalf("exec wipe: %v", err)
|
t.Fatalf("exec wipe: %v", err)
|
||||||
}
|
}
|
||||||
if name == "people" {
|
if name == "people" {
|
||||||
exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool")
|
exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
|
||||||
exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1)
|
exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1)
|
||||||
exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
|
exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
|
||||||
exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO", 3)
|
exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
|
||||||
}
|
}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
@ -105,12 +108,18 @@ func TestQueryRow(t *testing.T) {
|
|||||||
defer closeDB(t, db)
|
defer closeDB(t, db)
|
||||||
var name string
|
var name string
|
||||||
var age int
|
var age int
|
||||||
|
var birthday time.Time
|
||||||
|
|
||||||
err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age)
|
err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age)
|
||||||
if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") {
|
if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") {
|
||||||
t.Errorf("expected error from wrong number of arguments; actually got: %v", err)
|
t.Errorf("expected error from wrong number of arguments; actually got: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = db.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday)
|
||||||
|
if err != nil || !birthday.Equal(chrisBirthday) {
|
||||||
|
t.Errorf("chris birthday = %v, err = %v; want %v", birthday, err, chrisBirthday)
|
||||||
|
}
|
||||||
|
|
||||||
err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name)
|
err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("age QueryRow+Scan: %v", err)
|
t.Fatalf("age QueryRow+Scan: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user