diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-02 16:38:43 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-02 16:38:43 +0000 |
commit | cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce (patch) | |
tree | efa0c55763b34cbc633bc494c2743d1b5d9aaff3 /libgo/go/database | |
parent | ff2f581b00ac6759f6366c16ef902c935163aa13 (diff) | |
download | gcc-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.go | 12 | ||||
-rw-r--r-- | libgo/go/database/sql/convert_test.go | 22 | ||||
-rw-r--r-- | libgo/go/database/sql/driver/types.go | 7 | ||||
-rw-r--r-- | libgo/go/database/sql/driver/types_test.go | 4 | ||||
-rw-r--r-- | libgo/go/database/sql/sql.go | 60 | ||||
-rw-r--r-- | libgo/go/database/sql/sql_test.go | 32 |
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) |