open-vault/vendor/github.com/lib/pq/conn_go18.go

132 lines
2.6 KiB
Go
Raw Normal View History

// +build go1.8
2017-02-02 21:19:55 +00:00
package pq
import (
"context"
2017-06-05 14:50:46 +00:00
"database/sql"
2017-02-02 21:19:55 +00:00
"database/sql/driver"
2017-06-05 14:50:46 +00:00
"fmt"
2017-03-31 00:03:13 +00:00
"io"
"io/ioutil"
2017-02-02 21:19:55 +00:00
)
// Implement the "QueryerContext" interface
func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
list := make([]driver.Value, len(args))
for i, nv := range args {
list[i] = nv.Value
}
2017-03-31 00:03:13 +00:00
finish := cn.watchCancel(ctx)
2017-02-02 21:19:55 +00:00
r, err := cn.query(query, list)
if err != nil {
2017-06-05 14:50:46 +00:00
if finish != nil {
finish()
}
2017-02-02 21:19:55 +00:00
return nil, err
}
2017-03-31 00:03:13 +00:00
r.finish = finish
2017-02-02 21:19:55 +00:00
return r, nil
}
// Implement the "ExecerContext" interface
func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
list := make([]driver.Value, len(args))
for i, nv := range args {
list[i] = nv.Value
}
2017-03-31 00:03:13 +00:00
if finish := cn.watchCancel(ctx); finish != nil {
defer finish()
2017-02-02 21:19:55 +00:00
}
return cn.Exec(query, list)
}
// Implement the "ConnBeginTx" interface
func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
2017-06-05 14:50:46 +00:00
var mode string
switch sql.IsolationLevel(opts.Isolation) {
case sql.LevelDefault:
// Don't touch mode: use the server's default
case sql.LevelReadUncommitted:
mode = " ISOLATION LEVEL READ UNCOMMITTED"
case sql.LevelReadCommitted:
mode = " ISOLATION LEVEL READ COMMITTED"
case sql.LevelRepeatableRead:
mode = " ISOLATION LEVEL REPEATABLE READ"
case sql.LevelSerializable:
mode = " ISOLATION LEVEL SERIALIZABLE"
default:
return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
2017-02-02 21:19:55 +00:00
}
2017-06-05 14:50:46 +00:00
2017-02-02 21:19:55 +00:00
if opts.ReadOnly {
2017-06-05 14:50:46 +00:00
mode += " READ ONLY"
} else {
mode += " READ WRITE"
2017-02-02 21:19:55 +00:00
}
2017-06-05 14:50:46 +00:00
tx, err := cn.begin(mode)
2017-02-02 21:19:55 +00:00
if err != nil {
return nil, err
}
2017-03-31 00:03:13 +00:00
cn.txnFinish = cn.watchCancel(ctx)
2017-02-02 21:19:55 +00:00
return tx, nil
}
2017-03-31 00:03:13 +00:00
func (cn *conn) watchCancel(ctx context.Context) func() {
if done := ctx.Done(); done != nil {
finished := make(chan struct{})
go func() {
select {
case <-done:
_ = cn.cancel()
2017-03-31 00:03:13 +00:00
finished <- struct{}{}
case <-finished:
}
}()
return func() {
select {
case <-finished:
case finished <- struct{}{}:
}
2017-02-02 21:19:55 +00:00
}
2017-03-31 00:03:13 +00:00
}
return nil
2017-02-02 21:19:55 +00:00
}
func (cn *conn) cancel() error {
c, err := dial(cn.dialer, cn.opts)
2017-02-02 21:19:55 +00:00
if err != nil {
2017-03-31 00:03:13 +00:00
return err
2017-02-02 21:19:55 +00:00
}
2017-03-31 00:03:13 +00:00
defer c.Close()
{
can := conn{
c: c,
}
err = can.ssl(cn.opts)
if err != nil {
return err
}
2017-02-02 21:19:55 +00:00
2017-03-31 00:03:13 +00:00
w := can.writeBuf(0)
w.int32(80877102) // cancel request code
w.int32(cn.processID)
w.int32(cn.secretKey)
2017-02-02 21:19:55 +00:00
2017-03-31 00:03:13 +00:00
if err := can.sendStartupPacket(w); err != nil {
return err
}
}
2017-02-02 21:19:55 +00:00
2017-03-31 00:03:13 +00:00
// Read until EOF to ensure that the server received the cancel.
{
_, err := io.Copy(ioutil.Discard, c)
return err
}
2017-02-02 21:19:55 +00:00
}