diff options
Diffstat (limited to 'src/pkg/database/sql/sql.go')
-rw-r--r-- | src/pkg/database/sql/sql.go | 118 |
1 files changed, 64 insertions, 54 deletions
diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go index 34a765210..62b551d89 100644 --- a/src/pkg/database/sql/sql.go +++ b/src/pkg/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 @@ -62,8 +62,8 @@ func (ns *NullString) ScanInto(value interface{}) error { return convertAssign(&ns.String, value) } -// SubsetValue implements the driver SubsetValuer interface. -func (ns NullString) SubsetValue() (interface{}, error) { +// Value implements the driver Valuer interface. +func (ns NullString) Value() (driver.Value, error) { if !ns.Valid { return nil, 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 @@ -88,8 +88,8 @@ func (n *NullInt64) ScanInto(value interface{}) error { return convertAssign(&n.Int64, value) } -// SubsetValue implements the driver SubsetValuer interface. -func (n NullInt64) SubsetValue() (interface{}, error) { +// Value implements the driver Valuer interface. +func (n NullInt64) Value() (driver.Value, error) { if !n.Valid { return nil, 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 @@ -114,8 +114,8 @@ func (n *NullFloat64) ScanInto(value interface{}) error { return convertAssign(&n.Float64, value) } -// SubsetValue implements the driver SubsetValuer interface. -func (n NullFloat64) SubsetValue() (interface{}, error) { +// Value implements the driver Valuer interface. +func (n NullFloat64) Value() (driver.Value, error) { if !n.Valid { return nil, 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 @@ -140,30 +140,32 @@ func (n *NullBool) ScanInto(value interface{}) error { return convertAssign(&n.Bool, value) } -// SubsetValue implements the driver SubsetValuer interface. -func (n NullBool) SubsetValue() (interface{}, error) { +// Value implements the driver Valuer interface. +func (n NullBool) Value() (driver.Value, error) { if !n.Valid { return nil, nil } 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() @@ -521,12 +523,19 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) { } defer tx.releaseConn() + sargs, err := subsetTypeArgs(args) + if err != nil { + return nil, err + } + if execer, ok := ci.(driver.Execer); ok { - resi, err := execer.Exec(query, args) - if err != nil { + resi, err := execer.Exec(query, sargs) + if err == nil { + return result{resi}, nil + } + if err != driver.ErrSkip { return nil, err } - return result{resi}, nil } sti, err := ci.Prepare(query) @@ -535,11 +544,6 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) { } defer sti.Close() - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - resi, err := sti.Exec(sargs) if err != nil { return nil, err @@ -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 { @@ -614,19 +618,21 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) { return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args)) } + sargs := make([]driver.Value, len(args)) + // Convert args to subset types. if cc, ok := si.(driver.ColumnConverter); ok { for n, arg := range args { // First, see if the value itself knows how to convert // itself to a driver type. For example, a NullString // struct changing into a string or nil. - if svi, ok := arg.(driver.SubsetValuer); ok { - sv, err := svi.SubsetValue() + if svi, ok := arg.(driver.Valuer); ok { + sv, err := svi.Value() if err != nil { - return nil, fmt.Errorf("sql: argument index %d from SubsetValue: %v", n, err) + return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err) } - if !driver.IsParameterSubsetType(sv) { - return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from SubsetValue", n, sv) + if !driver.IsValue(sv) { + return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv) } arg = sv } @@ -638,25 +644,25 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) { // truncated), or that a nil can't go into a NOT NULL // column before going across the network to get the // same error. - args[n], err = cc.ColumnConverter(n).ConvertValue(arg) + sargs[n], err = cc.ColumnConverter(n).ConvertValue(arg) if err != nil { return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) } - if !driver.IsParameterSubsetType(args[n]) { + if !driver.IsValue(sargs[n]) { return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T", - arg, args[n]) + arg, sargs[n]) } } } else { for n, arg := range args { - args[n], err = driver.DefaultParameterConverter.ConvertValue(arg) + sargs[n], err = driver.DefaultParameterConverter.ConvertValue(arg) if err != nil { return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) } } } - resi, err := si.Exec(args) + resi, err := si.Exec(sargs) if err != nil { return nil, err } @@ -767,7 +773,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 { @@ -825,7 +831,7 @@ type Rows struct { rowsi driver.Rows closed bool - lastcols []interface{} + lastcols []driver.Value lasterr error closeStmt *Stmt // if non-nil, statement to Close on close } @@ -842,7 +848,7 @@ func (rs *Rows) Next() bool { return false } if rs.lastcols == nil { - rs.lastcols = make([]interface{}, len(rs.rowsi.Columns())) + rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns())) } rs.lasterr = rs.rowsi.Next(rs.lastcols) if rs.lasterr == io.EOF { @@ -880,6 +886,10 @@ func (rs *Rows) Columns() ([]string, error) { // be modified and held indefinitely. The copy can be avoided by using // an argument of type *RawBytes instead; see the documentation for // RawBytes for restrictions on its use. +// +// If an argument has type *interface{}, Scan copies the value +// provided by the underlying driver without conversion. If the value +// is of type []byte, a copy is made and the caller owns the result. func (rs *Rows) Scan(dest ...interface{}) error { if rs.closed { return errors.New("sql: Rows closed") |