connection_go18.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
  2. //
  3. // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public
  6. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  7. // You can obtain one at http://mozilla.org/MPL/2.0/.
  8. //go:build go1.8
  9. // +build go1.8
  10. package mysql
  11. import (
  12. "context"
  13. "database/sql"
  14. "database/sql/driver"
  15. )
  16. // Ping implements driver.Pinger interface
  17. func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
  18. if mc.closed.IsSet() {
  19. errLog.Print(ErrInvalidConn)
  20. return driver.ErrBadConn
  21. }
  22. if err = mc.watchCancel(ctx); err != nil {
  23. return
  24. }
  25. defer mc.finish()
  26. if err = mc.writeCommandPacket(comPing); err != nil {
  27. return
  28. }
  29. return mc.readResultOK()
  30. }
  31. // BeginTx implements driver.ConnBeginTx interface
  32. func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
  33. if err := mc.watchCancel(ctx); err != nil {
  34. return nil, err
  35. }
  36. defer mc.finish()
  37. if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
  38. level, err := mapIsolationLevel(opts.Isolation)
  39. if err != nil {
  40. return nil, err
  41. }
  42. err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
  43. if err != nil {
  44. return nil, err
  45. }
  46. }
  47. return mc.begin(opts.ReadOnly)
  48. }
  49. func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
  50. dargs, err := namedValueToValue(args)
  51. if err != nil {
  52. return nil, err
  53. }
  54. if err := mc.watchCancel(ctx); err != nil {
  55. return nil, err
  56. }
  57. rows, err := mc.query(query, dargs)
  58. if err != nil {
  59. mc.finish()
  60. return nil, err
  61. }
  62. rows.finish = mc.finish
  63. return rows, err
  64. }
  65. func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
  66. dargs, err := namedValueToValue(args)
  67. if err != nil {
  68. return nil, err
  69. }
  70. if err := mc.watchCancel(ctx); err != nil {
  71. return nil, err
  72. }
  73. defer mc.finish()
  74. return mc.Exec(query, dargs)
  75. }
  76. func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
  77. if err := mc.watchCancel(ctx); err != nil {
  78. return nil, err
  79. }
  80. stmt, err := mc.Prepare(query)
  81. mc.finish()
  82. if err != nil {
  83. return nil, err
  84. }
  85. select {
  86. default:
  87. case <-ctx.Done():
  88. stmt.Close()
  89. return nil, ctx.Err()
  90. }
  91. return stmt, nil
  92. }
  93. func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
  94. dargs, err := namedValueToValue(args)
  95. if err != nil {
  96. return nil, err
  97. }
  98. if err := stmt.mc.watchCancel(ctx); err != nil {
  99. return nil, err
  100. }
  101. rows, err := stmt.query(dargs)
  102. if err != nil {
  103. stmt.mc.finish()
  104. return nil, err
  105. }
  106. rows.finish = stmt.mc.finish
  107. return rows, err
  108. }
  109. func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
  110. dargs, err := namedValueToValue(args)
  111. if err != nil {
  112. return nil, err
  113. }
  114. if err := stmt.mc.watchCancel(ctx); err != nil {
  115. return nil, err
  116. }
  117. defer stmt.mc.finish()
  118. return stmt.Exec(dargs)
  119. }
  120. func (mc *mysqlConn) watchCancel(ctx context.Context) error {
  121. if mc.watching {
  122. // Reach here if canceled,
  123. // so the connection is already invalid
  124. mc.cleanup()
  125. return nil
  126. }
  127. // When ctx is already cancelled, don't watch it.
  128. if err := ctx.Err(); err != nil {
  129. return err
  130. }
  131. // When ctx is not cancellable, don't watch it.
  132. if ctx.Done() == nil {
  133. return nil
  134. }
  135. // When watcher is not alive, can't watch it.
  136. if mc.watcher == nil {
  137. return nil
  138. }
  139. mc.watching = true
  140. mc.watcher <- ctx
  141. return nil
  142. }
  143. func (mc *mysqlConn) startWatcher() {
  144. watcher := make(chan mysqlContext, 1)
  145. mc.watcher = watcher
  146. finished := make(chan struct{})
  147. mc.finished = finished
  148. go func() {
  149. for {
  150. var ctx mysqlContext
  151. select {
  152. case ctx = <-watcher:
  153. case <-mc.closech:
  154. return
  155. }
  156. select {
  157. case <-ctx.Done():
  158. mc.cancel(ctx.Err())
  159. case <-finished:
  160. case <-mc.closech:
  161. return
  162. }
  163. }
  164. }()
  165. }
  166. func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
  167. nv.Value, err = converter{}.ConvertValue(nv.Value)
  168. return
  169. }
  170. // ResetSession implements driver.SessionResetter.
  171. // (From Go 1.10)
  172. func (mc *mysqlConn) ResetSession(ctx context.Context) error {
  173. if mc.closed.IsSet() {
  174. return driver.ErrBadConn
  175. }
  176. return nil
  177. }