You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

conn_go18.go 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package pq
  2. import (
  3. "context"
  4. "database/sql"
  5. "database/sql/driver"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "time"
  10. )
  11. // Implement the "QueryerContext" interface
  12. func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
  13. list := make([]driver.Value, len(args))
  14. for i, nv := range args {
  15. list[i] = nv.Value
  16. }
  17. finish := cn.watchCancel(ctx)
  18. r, err := cn.query(query, list)
  19. if err != nil {
  20. if finish != nil {
  21. finish()
  22. }
  23. return nil, err
  24. }
  25. r.finish = finish
  26. return r, nil
  27. }
  28. // Implement the "ExecerContext" interface
  29. func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
  30. list := make([]driver.Value, len(args))
  31. for i, nv := range args {
  32. list[i] = nv.Value
  33. }
  34. if finish := cn.watchCancel(ctx); finish != nil {
  35. defer finish()
  36. }
  37. return cn.Exec(query, list)
  38. }
  39. // Implement the "ConnBeginTx" interface
  40. func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
  41. var mode string
  42. switch sql.IsolationLevel(opts.Isolation) {
  43. case sql.LevelDefault:
  44. // Don't touch mode: use the server's default
  45. case sql.LevelReadUncommitted:
  46. mode = " ISOLATION LEVEL READ UNCOMMITTED"
  47. case sql.LevelReadCommitted:
  48. mode = " ISOLATION LEVEL READ COMMITTED"
  49. case sql.LevelRepeatableRead:
  50. mode = " ISOLATION LEVEL REPEATABLE READ"
  51. case sql.LevelSerializable:
  52. mode = " ISOLATION LEVEL SERIALIZABLE"
  53. default:
  54. return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
  55. }
  56. if opts.ReadOnly {
  57. mode += " READ ONLY"
  58. } else {
  59. mode += " READ WRITE"
  60. }
  61. tx, err := cn.begin(mode)
  62. if err != nil {
  63. return nil, err
  64. }
  65. cn.txnFinish = cn.watchCancel(ctx)
  66. return tx, nil
  67. }
  68. func (cn *conn) Ping(ctx context.Context) error {
  69. if finish := cn.watchCancel(ctx); finish != nil {
  70. defer finish()
  71. }
  72. rows, err := cn.simpleQuery("SELECT 'lib/pq ping test';")
  73. if err != nil {
  74. return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger
  75. }
  76. rows.Close()
  77. return nil
  78. }
  79. func (cn *conn) watchCancel(ctx context.Context) func() {
  80. if done := ctx.Done(); done != nil {
  81. finished := make(chan struct{})
  82. go func() {
  83. select {
  84. case <-done:
  85. // At this point the function level context is canceled,
  86. // so it must not be used for the additional network
  87. // request to cancel the query.
  88. // Create a new context to pass into the dial.
  89. ctxCancel, cancel := context.WithTimeout(context.Background(), time.Second*10)
  90. defer cancel()
  91. _ = cn.cancel(ctxCancel)
  92. finished <- struct{}{}
  93. case <-finished:
  94. }
  95. }()
  96. return func() {
  97. select {
  98. case <-finished:
  99. case finished <- struct{}{}:
  100. }
  101. }
  102. }
  103. return nil
  104. }
  105. func (cn *conn) cancel(ctx context.Context) error {
  106. c, err := dial(ctx, cn.dialer, cn.opts)
  107. if err != nil {
  108. return err
  109. }
  110. defer c.Close()
  111. {
  112. can := conn{
  113. c: c,
  114. }
  115. err = can.ssl(cn.opts)
  116. if err != nil {
  117. return err
  118. }
  119. w := can.writeBuf(0)
  120. w.int32(80877102) // cancel request code
  121. w.int32(cn.processID)
  122. w.int32(cn.secretKey)
  123. if err := can.sendStartupPacket(w); err != nil {
  124. return err
  125. }
  126. }
  127. // Read until EOF to ensure that the server received the cancel.
  128. {
  129. _, err := io.Copy(ioutil.Discard, c)
  130. return err
  131. }
  132. }