aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/exp/sql/driver
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2011-11-02 11:46:04 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2011-11-02 11:46:04 -0700
commit8089e578124227a322a77f9c5599d2244f9d0cfc (patch)
tree6a9ea263df2f5b4d61a3862c4d61b50bd8397106 /src/pkg/exp/sql/driver
parentcefee3c919221a38d6eb93c8199d3d88ad5ae0b7 (diff)
downloadgo-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.go14
-rw-r--r--src/pkg/exp/sql/driver/types.go62
-rw-r--r--src/pkg/exp/sql/driver/types_test.go57
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)
+ }
+ }
+}