summaryrefslogtreecommitdiff
path: root/src/pkg/database/sql/sql.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/database/sql/sql.go')
-rw-r--r--src/pkg/database/sql/sql.go118
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")