aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/database
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-03-02 16:38:43 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-03-02 16:38:43 +0000
commitcbb6491d76c7aa81cdf5d3b3a81386129c5e2fce (patch)
treeefa0c55763b34cbc633bc494c2743d1b5d9aaff3 /libgo/go/database
parentff2f581b00ac6759f6366c16ef902c935163aa13 (diff)
downloadgcc-cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce.zip
gcc-cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce.tar.gz
gcc-cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce.tar.bz2
libgo: Update to weekly.2012-02-14 release.
From-SVN: r184798
Diffstat (limited to 'libgo/go/database')
-rw-r--r--libgo/go/database/sql/convert.go12
-rw-r--r--libgo/go/database/sql/convert_test.go22
-rw-r--r--libgo/go/database/sql/driver/types.go7
-rw-r--r--libgo/go/database/sql/driver/types_test.go4
-rw-r--r--libgo/go/database/sql/sql.go60
-rw-r--r--libgo/go/database/sql/sql_test.go32
6 files changed, 107 insertions, 30 deletions
diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go
index 4924ac1..4afa2be 100644
--- a/libgo/go/database/sql/convert.go
+++ b/libgo/go/database/sql/convert.go
@@ -90,8 +90,8 @@ func convertAssign(dest, src interface{}) error {
return nil
}
- if scanner, ok := dest.(ScannerInto); ok {
- return scanner.ScanInto(src)
+ if scanner, ok := dest.(Scanner); ok {
+ return scanner.Scan(src)
}
dpv := reflect.ValueOf(dest)
@@ -110,6 +110,14 @@ func convertAssign(dest, src interface{}) error {
}
switch dv.Kind() {
+ case reflect.Ptr:
+ if src == nil {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ } else {
+ dv.Set(reflect.New(dv.Type().Elem()))
+ return convertAssign(dv.Interface(), src)
+ }
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s := asString(src)
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go
index 34ee939..9c362d7 100644
--- a/libgo/go/database/sql/convert_test.go
+++ b/libgo/go/database/sql/convert_test.go
@@ -13,6 +13,7 @@ import (
)
var someTime = time.Unix(123, 0)
+var answer int64 = 42
type conversionTest struct {
s, d interface{} // source and destination
@@ -27,6 +28,8 @@ type conversionTest struct {
wantbool bool // used if d is of type *bool
wanterr string
wantiface interface{}
+ wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr
+ wantnil bool // if true, *d must be *int64(nil)
}
// Target variables for scanning into.
@@ -42,6 +45,7 @@ var (
scanf32 float32
scanf64 float64
scantime time.Time
+ scanptr *int64
scaniface interface{}
)
@@ -98,6 +102,10 @@ var conversionTests = []conversionTest{
{s: "1.5", d: &scanf32, wantf32: float32(1.5)},
{s: "1.5", d: &scanf64, wantf64: float64(1.5)},
+ // Pointers
+ {s: interface{}(nil), d: &scanptr, wantnil: true},
+ {s: int64(42), d: &scanptr, wantptr: &answer},
+
// To interface{}
{s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
{s: int64(1), d: &scaniface, wantiface: int64(1)},
@@ -107,6 +115,10 @@ var conversionTests = []conversionTest{
{s: nil, d: &scaniface},
}
+func intPtrValue(intptr interface{}) interface{} {
+ return reflect.Indirect(reflect.Indirect(reflect.ValueOf(intptr))).Int()
+}
+
func intValue(intptr interface{}) int64 {
return reflect.Indirect(reflect.ValueOf(intptr)).Int()
}
@@ -162,6 +174,16 @@ func TestConversions(t *testing.T) {
if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) {
errf("want time %v, got %v", ct.wanttime, timeValue(ct.d))
}
+ if ct.wantnil && *ct.d.(**int64) != nil {
+ errf("want nil, got %v", intPtrValue(ct.d))
+ }
+ if ct.wantptr != nil {
+ if *ct.d.(**int64) == nil {
+ errf("want pointer to %v, got nil", *ct.wantptr)
+ } else if *ct.wantptr != intPtrValue(ct.d) {
+ errf("want pointer to %v, got %v", *ct.wantptr, intPtrValue(ct.d))
+ }
+ }
if ifptr, ok := ct.d.(*interface{}); ok {
if !reflect.DeepEqual(ct.wantiface, scaniface) {
errf("want interface %#v, got %#v", ct.wantiface, scaniface)
diff --git a/libgo/go/database/sql/driver/types.go b/libgo/go/database/sql/driver/types.go
index f383885..ce3c943 100644
--- a/libgo/go/database/sql/driver/types.go
+++ b/libgo/go/database/sql/driver/types.go
@@ -248,6 +248,13 @@ func (defaultConverter) ConvertValue(v interface{}) (interface{}, error) {
rv := reflect.ValueOf(v)
switch rv.Kind() {
+ case reflect.Ptr:
+ // indirect pointers
+ if rv.IsNil() {
+ return nil, nil
+ } else {
+ return defaultConverter{}.ConvertValue(rv.Elem().Interface())
+ }
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
diff --git a/libgo/go/database/sql/driver/types_test.go b/libgo/go/database/sql/driver/types_test.go
index 966bc6b..ab82bca 100644
--- a/libgo/go/database/sql/driver/types_test.go
+++ b/libgo/go/database/sql/driver/types_test.go
@@ -18,6 +18,7 @@ type valueConverterTest struct {
}
var now = time.Now()
+var answer int64 = 42
var valueConverterTests = []valueConverterTest{
{Bool, "true", true, ""},
@@ -37,6 +38,9 @@ var valueConverterTests = []valueConverterTest{
{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"},
{DefaultParameterConverter, now, now, ""},
+ {DefaultParameterConverter, (*int64)(nil), nil, ""},
+ {DefaultParameterConverter, &answer, answer, ""},
+ {DefaultParameterConverter, &now, now, ""},
}
func TestValueConverters(t *testing.T) {
diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go
index 436d495..f14a98c 100644
--- a/libgo/go/database/sql/sql.go
+++ b/libgo/go/database/sql/sql.go
@@ -35,7 +35,7 @@ func Register(name string, driver driver.Driver) {
type RawBytes []byte
// NullString represents a string that may be null.
-// NullString implements the ScannerInto interface so
+// NullString implements the Scanner interface so
// it can be used as a scan destination:
//
// var s NullString
@@ -52,8 +52,8 @@ type NullString struct {
Valid bool // Valid is true if String is not NULL
}
-// ScanInto implements the ScannerInto interface.
-func (ns *NullString) ScanInto(value interface{}) error {
+// Scan implements the Scanner interface.
+func (ns *NullString) Scan(value interface{}) error {
if value == nil {
ns.String, ns.Valid = "", false
return nil
@@ -71,15 +71,15 @@ func (ns NullString) SubsetValue() (interface{}, error) {
}
// NullInt64 represents an int64 that may be null.
-// NullInt64 implements the ScannerInto interface so
+// NullInt64 implements the Scanner interface so
// it can be used as a scan destination, similar to NullString.
type NullInt64 struct {
Int64 int64
Valid bool // Valid is true if Int64 is not NULL
}
-// ScanInto implements the ScannerInto interface.
-func (n *NullInt64) ScanInto(value interface{}) error {
+// Scan implements the Scanner interface.
+func (n *NullInt64) Scan(value interface{}) error {
if value == nil {
n.Int64, n.Valid = 0, false
return nil
@@ -97,15 +97,15 @@ func (n NullInt64) SubsetValue() (interface{}, error) {
}
// NullFloat64 represents a float64 that may be null.
-// NullFloat64 implements the ScannerInto interface so
+// NullFloat64 implements the Scanner interface so
// it can be used as a scan destination, similar to NullString.
type NullFloat64 struct {
Float64 float64
Valid bool // Valid is true if Float64 is not NULL
}
-// ScanInto implements the ScannerInto interface.
-func (n *NullFloat64) ScanInto(value interface{}) error {
+// Scan implements the Scanner interface.
+func (n *NullFloat64) Scan(value interface{}) error {
if value == nil {
n.Float64, n.Valid = 0, false
return nil
@@ -123,15 +123,15 @@ func (n NullFloat64) SubsetValue() (interface{}, error) {
}
// NullBool represents a bool that may be null.
-// NullBool implements the ScannerInto interface so
+// NullBool implements the Scanner interface so
// it can be used as a scan destination, similar to NullString.
type NullBool struct {
Bool bool
Valid bool // Valid is true if Bool is not NULL
}
-// ScanInto implements the ScannerInto interface.
-func (n *NullBool) ScanInto(value interface{}) error {
+// Scan implements the Scanner interface.
+func (n *NullBool) Scan(value interface{}) error {
if value == nil {
n.Bool, n.Valid = false, false
return nil
@@ -148,22 +148,24 @@ func (n NullBool) SubsetValue() (interface{}, error) {
return n.Bool, nil
}
-// ScannerInto is an interface used by Scan.
-type ScannerInto interface {
- // ScanInto assigns a value from a database driver.
+// Scanner is an interface used by Scan.
+type Scanner interface {
+ // Scan assigns a value from a database driver.
//
- // The value will be of one of the following restricted
+ // The src value will be of one of the following restricted
// set of types:
//
// int64
// float64
// bool
// []byte
+ // string
+ // time.Time
// nil - for NULL values
//
// An error should be returned if the value can not be stored
// without loss of information.
- ScanInto(value interface{}) error
+ Scan(src interface{}) error
}
// ErrNoRows is returned by Scan when QueryRow doesn't return a
@@ -368,7 +370,7 @@ func (db *DB) Begin() (*Tx, error) {
}, nil
}
-// DriverDatabase returns the database's underlying driver.
+// Driver returns the database's underlying driver.
func (db *DB) Driver() driver.Driver {
return db.driver
}
@@ -378,7 +380,7 @@ func (db *DB) Driver() driver.Driver {
// A transaction must end with a call to Commit or Rollback.
//
// After a call to Commit or Rollback, all operations on the
-// transaction fail with ErrTransactionFinished.
+// transaction fail with ErrTxDone.
type Tx struct {
db *DB
@@ -393,11 +395,11 @@ type Tx struct {
// done transitions from false to true exactly once, on Commit
// or Rollback. once done, all operations fail with
- // ErrTransactionFinished.
+ // ErrTxDone.
done bool
}
-var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back")
+var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
func (tx *Tx) close() {
if tx.done {
@@ -411,7 +413,7 @@ func (tx *Tx) close() {
func (tx *Tx) grabConn() (driver.Conn, error) {
if tx.done {
- return nil, ErrTransactionFinished
+ return nil, ErrTxDone
}
tx.cimu.Lock()
return tx.ci, nil
@@ -424,7 +426,7 @@ func (tx *Tx) releaseConn() {
// Commit commits the transaction.
func (tx *Tx) Commit() error {
if tx.done {
- return ErrTransactionFinished
+ return ErrTxDone
}
defer tx.close()
return tx.txi.Commit()
@@ -433,7 +435,7 @@ func (tx *Tx) Commit() error {
// Rollback aborts the transaction.
func (tx *Tx) Rollback() error {
if tx.done {
- return ErrTransactionFinished
+ return ErrTxDone
}
defer tx.close()
return tx.txi.Rollback()
@@ -523,10 +525,12 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
if execer, ok := ci.(driver.Execer); ok {
resi, err := execer.Exec(query, args)
- if err != nil {
+ if err == nil {
+ return result{resi}, nil
+ }
+ if err != driver.ErrSkip {
return nil, err
}
- return result{resi}, nil
}
sti, err := ci.Prepare(query)
@@ -550,7 +554,7 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
// Query executes a query that returns rows, typically a SELECT.
func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
if tx.done {
- return nil, ErrTransactionFinished
+ return nil, ErrTxDone
}
stmt, err := tx.Prepare(query)
if err != nil {
@@ -767,7 +771,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
// Example usage:
//
// var name string
-// err := nameByUseridStmt.QueryRow(id).Scan(&s)
+// err := nameByUseridStmt.QueryRow(id).Scan(&name)
func (s *Stmt) QueryRow(args ...interface{}) *Row {
rows, err := s.Query(args...)
if err != nil {
diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go
index c5cadad..c985a10 100644
--- a/libgo/go/database/sql/sql_test.go
+++ b/libgo/go/database/sql/sql_test.go
@@ -386,6 +386,38 @@ func TestNullByteSlice(t *testing.T) {
}
}
+func TestPointerParamsAndScans(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t|id=int32,name=nullstring")
+
+ bob := "bob"
+ var name *string
+
+ name = &bob
+ exec(t, db, "INSERT|t|id=10,name=?", name)
+ name = nil
+ exec(t, db, "INSERT|t|id=20,name=?", name)
+
+ err := db.QueryRow("SELECT|t|name|id=?", 10).Scan(&name)
+ if err != nil {
+ t.Fatalf("querying id 10: %v", err)
+ }
+ if name == nil {
+ t.Errorf("id 10's name = nil; want bob")
+ } else if *name != "bob" {
+ t.Errorf("id 10's name = %q; want bob", *name)
+ }
+
+ err = db.QueryRow("SELECT|t|name|id=?", 20).Scan(&name)
+ if err != nil {
+ t.Fatalf("querying id 20: %v", err)
+ }
+ if name != nil {
+ t.Errorf("id 20 = %q; want nil", *name)
+ }
+}
+
func TestQueryRowClosingStmt(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)