aboutsummaryrefslogtreecommitdiff
path: root/src/database/sql/sql.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/database/sql/sql.go')
-rw-r--r--src/database/sql/sql.go89
1 files changed, 45 insertions, 44 deletions
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index a620707b2d..0fa7c34a13 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -8,14 +8,16 @@
// The sql package must be used in conjunction with a database driver.
// See https://golang.org/s/sqldrivers for a list of drivers.
//
-// For more usage examples, see the wiki page at
+// Drivers that do not support context cancelation will not return until
+// after the query is completed.
+//
+// For usage examples, see the wiki page at
// https://golang.org/s/sqlwiki.
package sql
import (
"context"
"database/sql/driver"
- "database/sql/internal"
"errors"
"fmt"
"io"
@@ -69,17 +71,26 @@ func Drivers() []string {
return list
}
-// A NamedArg used as an argument to Query or Exec
-// binds to the corresponding named parameter in the SQL statement.
+// A NamedArg is a named argument. NamedArg values may be used as
+// arguments to Query or Exec and bind to the corresponding named
+// parameter in the SQL statement.
+//
+// For a more concise way to create NamedArg values, see
+// the Named function.
type NamedArg struct {
_Named_Fields_Required struct{}
- // Name of the parameter placeholder. If empty the ordinal position in the
- // argument list will be used.
+ // Name is the name of the parameter placeholder.
+ //
+ // If empty, the ordinal position in the argument list will be
+ // used.
+ //
+ // Name must omit any symbol prefix.
Name string
- // Value of the parameter. It may be assigned the same value types as
- // the query arguments.
+ // Value is the value of the parameter.
+ // It may be assigned the same value types as the query
+ // arguments.
Value interface{}
}
@@ -103,12 +114,10 @@ func Named(name string, value interface{}) NamedArg {
return NamedArg{Name: name, Value: value}
}
-// IsolationLevel is the transaction isolation level stored in Context.
-// The IsolationLevel is set with IsolationContext and the context
-// should be passed to BeginContext.
+// IsolationLevel is the transaction isolation level used in TxOptions.
type IsolationLevel int
-// Various isolation levels that drivers may support in BeginContext.
+// Various isolation levels that drivers may support in BeginTx.
// If a driver does not support a given isolation level an error may be returned.
//
// See https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.
@@ -123,18 +132,12 @@ const (
LevelLinearizable
)
-// IsolationContext returns a new Context that carries the provided isolation level.
-// The context must contain the isolation level before beginning the transaction
-// with BeginContext.
-func IsolationContext(ctx context.Context, level IsolationLevel) context.Context {
- return context.WithValue(ctx, internal.IsolationLevelKey{}, driver.IsolationLevel(level))
-}
-
-// ReadOnlyWithContext returns a new Context that carries the provided
-// read-only transaction property. The context must contain the read-only property
-// before beginning the transaction with BeginContext.
-func ReadOnlyContext(ctx context.Context) context.Context {
- return context.WithValue(ctx, internal.ReadOnlyKey{}, true)
+// TxOptions holds the transaction options to be used in DB.BeginTx.
+type TxOptions struct {
+ // Isolation is the transaction isolation level.
+ // If zero, the driver or database's default level is used.
+ Isolation IsolationLevel
+ ReadOnly bool
}
// RawBytes is a byte slice that holds a reference to memory owned by
@@ -1299,28 +1302,27 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
return db.QueryRowContext(context.Background(), query, args...)
}
-// BeginContext starts a transaction.
+// BeginTx starts a transaction.
//
// The provided context is used until the transaction is committed or rolled back.
// If the context is canceled, the sql package will roll back
// the transaction. Tx.Commit will return an error if the context provided to
-// BeginContext is canceled.
+// BeginTx is canceled.
//
-// An isolation level may be set by setting the value in the context
-// before calling this. If a non-default isolation level is used
-// that the driver doesn't support an error will be returned. Different drivers
-// may have slightly different meanings for the same isolation level.
-func (db *DB) BeginContext(ctx context.Context) (*Tx, error) {
+// The provided TxOptions is optional and may be nil if defaults should be used.
+// If a non-default isolation level is used that the driver doesn't support,
+// an error will be returned.
+func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
var tx *Tx
var err error
for i := 0; i < maxBadConnRetries; i++ {
- tx, err = db.begin(ctx, cachedOrNewConn)
+ tx, err = db.begin(ctx, opts, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.begin(ctx, alwaysNewConn)
+ return db.begin(ctx, opts, alwaysNewConn)
}
return tx, err
}
@@ -1328,17 +1330,17 @@ func (db *DB) BeginContext(ctx context.Context) (*Tx, error) {
// Begin starts a transaction. The default isolation level is dependent on
// the driver.
func (db *DB) Begin() (*Tx, error) {
- return db.BeginContext(context.Background())
+ return db.BeginTx(context.Background(), nil)
}
-func (db *DB) begin(ctx context.Context, strategy connReuseStrategy) (tx *Tx, err error) {
+func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStrategy) (tx *Tx, err error) {
dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
var txi driver.Tx
withLock(dc, func() {
- txi, err = ctxDriverBegin(ctx, dc.ci)
+ txi, err = ctxDriverBegin(ctx, opts, dc.ci)
})
if err != nil {
db.putConn(dc, err)
@@ -1419,10 +1421,9 @@ func (tx *Tx) isDone() bool {
// that has already been committed or rolled back.
var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
+// close returns the connection to the pool and
+// must only be called by Tx.rollback or Tx.Commit.
func (tx *Tx) close(err error) {
- if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
- panic("double close") // internal error
- }
tx.db.putConn(tx.dc, err)
tx.cancel()
tx.dc = nil
@@ -1447,14 +1448,14 @@ func (tx *Tx) closePrepared() {
// Commit commits the transaction.
func (tx *Tx) Commit() error {
+ if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
+ return ErrTxDone
+ }
select {
default:
case <-tx.ctx.Done():
return tx.ctx.Err()
}
- if tx.isDone() {
- return ErrTxDone
- }
var err error
withLock(tx.dc, func() {
err = tx.txi.Commit()
@@ -1469,7 +1470,7 @@ func (tx *Tx) Commit() error {
// rollback aborts the transaction and optionally forces the pool to discard
// the connection.
func (tx *Tx) rollback(discardConn bool) error {
- if tx.isDone() {
+ if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
return ErrTxDone
}
var err error
@@ -2085,7 +2086,7 @@ func (rs *Rows) Next() bool {
}
// The driver is at the end of the current result set.
// Test to see if there is another result set after the current one.
- // Only close Rows if there is no futher result sets to read.
+ // Only close Rows if there is no further result sets to read.
if !nextResultSet.HasNextResultSet() {
rs.Close()
}