From ce6aa2ebdab0c6616ef17acc9282b0e168f5f21a Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Sun, 16 Oct 2016 23:11:55 -0700 Subject: database/sql: add context helper methods and transaction types Prior to this change, it was implied that transaction properties would be carried in the context value. However, no such properties were defined, not even common ones. Define two common properties: isolation level and read-only. Drivers may choose to support additional transaction properties. It is not expected any further transaction properties will be added in the future. Change-Id: I2f680115a14a1333c65ba6f943d9a1149d412918 Reviewed-on: https://go-review.googlesource.com/31258 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/database/sql/sql.go | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) (limited to 'src/database/sql/sql.go') diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index d363008993..3cef4b6404 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -15,6 +15,7 @@ package sql import ( "context" "database/sql/driver" + "database/sql/internal" "errors" "fmt" "io" @@ -89,6 +90,38 @@ func Param(name string, value interface{}) NamedParam { return NamedParam{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. +type IsolationLevel int + +// Various isolation levels that drivers may support in BeginContext. +// If a driver does not support a given isolation level an error may be returned. +const ( + LevelDefault IsolationLevel = iota + LevelReadUncommited + LevelReadCommited + LevelWriteCommited + LevelRepeatableRead + LevelSnapshot + LevelSerializable + 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) +} + // RawBytes is a byte slice that holds a reference to memory owned by // the database itself. After a Scan into a RawBytes, the slice is only // valid until the next call to Next, Scan, or Close. @@ -1224,7 +1257,10 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row { return db.QueryRowContext(context.Background(), query, args...) } -// BeginContext starts a transaction. If a non-default isolation level is used +// BeginContext starts a transaction. +// +// 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) { @@ -2212,9 +2248,9 @@ func (rs *Rows) isClosed() bool { return atomic.LoadInt32(&rs.closed) != 0 } -// Close closes the Rows, preventing further enumeration. If Next and -// NextResultSet both return -// false, the Rows are closed automatically and it will suffice to check the +// Close closes the Rows, preventing further enumeration. If Next is called +// and returns false and there are no further result sets, +// the Rows are closed automatically and it will suffice to check the // result of Err. Close is idempotent and does not affect the result of Err. func (rs *Rows) Close() error { if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) { -- cgit v1.3