diff options
| author | Brad Fitzpatrick <bradfitz@golang.org> | 2011-11-02 11:46:04 -0700 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2011-11-02 11:46:04 -0700 |
| commit | 8089e578124227a322a77f9c5599d2244f9d0cfc (patch) | |
| tree | 6a9ea263df2f5b4d61a3862c4d61b50bd8397106 /src/pkg/exp/sql/driver | |
| parent | cefee3c919221a38d6eb93c8199d3d88ad5ae0b7 (diff) | |
| download | go-8089e578124227a322a77f9c5599d2244f9d0cfc.tar.xz | |
exp/sql: finish transactions, flesh out types, docs
Fixes #2328 (float, bool)
R=rsc, r
CC=golang-dev
https://golang.org/cl/5294067
Diffstat (limited to 'src/pkg/exp/sql/driver')
| -rw-r--r-- | src/pkg/exp/sql/driver/driver.go | 14 | ||||
| -rw-r--r-- | src/pkg/exp/sql/driver/types.go | 62 | ||||
| -rw-r--r-- | src/pkg/exp/sql/driver/types_test.go | 57 |
3 files changed, 127 insertions, 6 deletions
diff --git a/src/pkg/exp/sql/driver/driver.go b/src/pkg/exp/sql/driver/driver.go index 52714e817a..6a51c34241 100644 --- a/src/pkg/exp/sql/driver/driver.go +++ b/src/pkg/exp/sql/driver/driver.go @@ -24,9 +24,13 @@ import "errors" // Driver is the interface that must be implemented by a database // driver. type Driver interface { - // Open returns a new or cached connection to the database. + // Open returns a new connection to the database. // The name is a string in a driver-specific format. // + // Open may return a cached connection (one previously + // closed), but doing so is unnecessary; the sql package + // maintains a pool of idle connections for efficient re-use. + // // The returned connection is only used by one goroutine at a // time. Open(name string) (Conn, error) @@ -59,8 +63,12 @@ type Conn interface { // Close invalidates and potentially stops any current // prepared statements and transactions, marking this - // connection as no longer in use. The driver may cache or - // close its underlying connection to its database. + // connection as no longer in use. + // + // Because the sql package maintains a free pool of + // connections and only calls Close when there's a surplus of + // idle connections, it shouldn't be necessary for drivers to + // do their own connection caching. Close() error // Begin starts and returns a new transaction. diff --git a/src/pkg/exp/sql/driver/types.go b/src/pkg/exp/sql/driver/types.go index 9faf32f671..6e0ce4339c 100644 --- a/src/pkg/exp/sql/driver/types.go +++ b/src/pkg/exp/sql/driver/types.go @@ -11,6 +11,21 @@ import ( ) // ValueConverter is the interface providing the ConvertValue method. +// +// Various implementations of ValueConverter are provided by the +// driver package to provide consistent implementations of conversions +// between drivers. The ValueConverters have several uses: +// +// * converting from the subset types as provided by the sql package +// into a database table's specific column type and making sure it +// fits, such as making sure a particular int64 fits in a +// table's uint16 column. +// +// * converting a value as given from the database into one of the +// subset types. +// +// * by the sql package, for converting from a driver's subset type +// to a user's type in a scan. type ValueConverter interface { // ConvertValue converts a value to a restricted subset type. ConvertValue(v interface{}) (interface{}, error) @@ -19,15 +34,56 @@ type ValueConverter interface { // Bool is a ValueConverter that converts input values to bools. // // The conversion rules are: -// - .... TODO(bradfitz): TBD +// - booleans are returned unchanged +// - for integer types, +// 1 is true +// 0 is false, +// other integers are an error +// - for strings and []byte, same rules as strconv.Atob +// - all other types are an error var Bool boolType type boolType struct{} var _ ValueConverter = boolType{} -func (boolType) ConvertValue(v interface{}) (interface{}, error) { - return nil, fmt.Errorf("TODO(bradfitz): bool conversions") +func (boolType) String() string { return "Bool" } + +func (boolType) ConvertValue(src interface{}) (interface{}, error) { + switch s := src.(type) { + case bool: + return s, nil + case string: + b, err := strconv.Atob(s) + if err != nil { + return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) + } + return b, nil + case []byte: + b, err := strconv.Atob(string(s)) + if err != nil { + return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) + } + return b, nil + } + + sv := reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + iv := sv.Int() + if iv == 1 || iv == 0 { + return iv == 1, nil + } + return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + uv := sv.Uint() + if uv == 1 || uv == 0 { + return uv == 1, nil + } + return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv) + } + + return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src) } // Int32 is a ValueConverter that converts input values to int64, diff --git a/src/pkg/exp/sql/driver/types_test.go b/src/pkg/exp/sql/driver/types_test.go new file mode 100644 index 0000000000..4b049e26e5 --- /dev/null +++ b/src/pkg/exp/sql/driver/types_test.go @@ -0,0 +1,57 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package driver + +import ( + "reflect" + "testing" +) + +type valueConverterTest struct { + c ValueConverter + in interface{} + out interface{} + err string +} + +var valueConverterTests = []valueConverterTest{ + {Bool, "true", true, ""}, + {Bool, "True", true, ""}, + {Bool, []byte("t"), true, ""}, + {Bool, true, true, ""}, + {Bool, "1", true, ""}, + {Bool, 1, true, ""}, + {Bool, int64(1), true, ""}, + {Bool, uint16(1), true, ""}, + {Bool, "false", false, ""}, + {Bool, false, false, ""}, + {Bool, "0", false, ""}, + {Bool, 0, false, ""}, + {Bool, int64(0), false, ""}, + {Bool, uint16(0), false, ""}, + {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"}, +} + +func TestValueConverters(t *testing.T) { + for i, tt := range valueConverterTests { + out, err := tt.c.ConvertValue(tt.in) + goterr := "" + if err != nil { + goterr = err.Error() + } + if goterr != tt.err { + t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q", + i, tt.c, tt.in, tt.in, goterr, tt.err) + } + if tt.err != "" { + continue + } + if !reflect.DeepEqual(out, tt.out) { + t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)", + i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out) + } + } +} |
