connection_go18.go 4.2 KB

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