1
+ // +build go1.9
2
+
1
3
package mysql
2
4
3
5
import (
6
+ "context"
4
7
"crypto/tls"
5
8
"crypto/x509"
6
9
"database/sql"
@@ -35,7 +38,9 @@ type Config struct {
35
38
}
36
39
37
40
type Mysql struct {
38
- db * sql.DB
41
+ // mysql RELEASE_LOCK must be called from the same conn, so
42
+ // just do everything over a single conn anyway.
43
+ conn * sql.Conn
39
44
isLocked bool
40
45
41
46
config * Config
@@ -67,8 +72,13 @@ func WithInstance(instance *sql.DB, config *Config) (database.Driver, error) {
67
72
config .MigrationsTable = DefaultMigrationsTable
68
73
}
69
74
75
+ conn , err := instance .Conn (context .Background ())
76
+ if err != nil {
77
+ return nil , err
78
+ }
79
+
70
80
mx := & Mysql {
71
- db : instance ,
81
+ conn : conn ,
72
82
config : config ,
73
83
}
74
84
@@ -148,7 +158,7 @@ func (m *Mysql) Open(url string) (database.Driver, error) {
148
158
}
149
159
150
160
func (m * Mysql ) Close () error {
151
- return m .db .Close ()
161
+ return m .conn .Close ()
152
162
}
153
163
154
164
func (m * Mysql ) Lock () error {
@@ -162,9 +172,9 @@ func (m *Mysql) Lock() error {
162
172
return err
163
173
}
164
174
165
- query := "SELECT GET_LOCK(?, 1 )"
175
+ query := "SELECT GET_LOCK(?, 10 )"
166
176
var success bool
167
- if err := m .db . QueryRow ( query , aid ).Scan (& success ); err != nil {
177
+ if err := m .conn . QueryRowContext ( context . Background (), query , aid ).Scan (& success ); err != nil {
168
178
return & database.Error {OrigErr : err , Err : "try lock failed" , Query : []byte (query )}
169
179
}
170
180
@@ -188,10 +198,14 @@ func (m *Mysql) Unlock() error {
188
198
}
189
199
190
200
query := `SELECT RELEASE_LOCK(?)`
191
- if _ , err := m .db . Exec ( query , aid ); err != nil {
201
+ if _ , err := m .conn . ExecContext ( context . Background (), query , aid ); err != nil {
192
202
return & database.Error {OrigErr : err , Query : []byte (query )}
193
203
}
194
204
205
+ // NOTE: RELEASE_LOCK could return NULL or (or 0 if the code is changed),
206
+ // in which case isLocked should be true until the timeout expires -- synchronizing
207
+ // these states is likely not worth trying to do; reconsider the necessity of isLocked.
208
+
195
209
m .isLocked = false
196
210
return nil
197
211
}
@@ -203,27 +217,28 @@ func (m *Mysql) Run(migration io.Reader) error {
203
217
}
204
218
205
219
query := string (migr [:])
206
- if _ , err := m .db . Exec ( query ); err != nil {
220
+ if _ , err := m .conn . ExecContext ( context . Background (), query ); err != nil {
207
221
return database.Error {OrigErr : err , Err : "migration failed" , Query : migr }
208
222
}
209
223
210
224
return nil
211
225
}
212
226
213
227
func (m * Mysql ) SetVersion (version int , dirty bool ) error {
214
- tx , err := m .db . Begin ( )
228
+ tx , err := m .conn . BeginTx ( context . Background (), & sql. TxOptions {} )
215
229
if err != nil {
216
230
return & database.Error {OrigErr : err , Err : "transaction start failed" }
217
231
}
218
232
219
233
query := "TRUNCATE `" + m .config .MigrationsTable + "`"
220
- if _ , err := m .db .Exec (query ); err != nil {
234
+ if _ , err := tx .ExecContext (context .Background (), query ); err != nil {
235
+ tx .Rollback ()
221
236
return & database.Error {OrigErr : err , Query : []byte (query )}
222
237
}
223
238
224
239
if version >= 0 {
225
240
query := "INSERT INTO `" + m .config .MigrationsTable + "` (version, dirty) VALUES (?, ?)"
226
- if _ , err := m . db . Exec ( query , version , dirty ); err != nil {
241
+ if _ , err := tx . ExecContext ( context . Background (), query , version , dirty ); err != nil {
227
242
tx .Rollback ()
228
243
return & database.Error {OrigErr : err , Query : []byte (query )}
229
244
}
@@ -238,7 +253,7 @@ func (m *Mysql) SetVersion(version int, dirty bool) error {
238
253
239
254
func (m * Mysql ) Version () (version int , dirty bool , err error ) {
240
255
query := "SELECT version, dirty FROM `" + m .config .MigrationsTable + "` LIMIT 1"
241
- err = m .db . QueryRow ( query ).Scan (& version , & dirty )
256
+ err = m .conn . QueryRowContext ( context . Background (), query ).Scan (& version , & dirty )
242
257
switch {
243
258
case err == sql .ErrNoRows :
244
259
return database .NilVersion , false , nil
@@ -259,7 +274,7 @@ func (m *Mysql) Version() (version int, dirty bool, err error) {
259
274
func (m * Mysql ) Drop () error {
260
275
// select all tables
261
276
query := `SHOW TABLES LIKE '%'`
262
- tables , err := m .db . Query ( query )
277
+ tables , err := m .conn . QueryContext ( context . Background (), query )
263
278
if err != nil {
264
279
return & database.Error {OrigErr : err , Query : []byte (query )}
265
280
}
@@ -281,7 +296,7 @@ func (m *Mysql) Drop() error {
281
296
// delete one by one ...
282
297
for _ , t := range tableNames {
283
298
query = "DROP TABLE IF EXISTS `" + t + "` CASCADE"
284
- if _ , err := m .db . Exec ( query ); err != nil {
299
+ if _ , err := m .conn . ExecContext ( context . Background (), query ); err != nil {
285
300
return & database.Error {OrigErr : err , Query : []byte (query )}
286
301
}
287
302
}
@@ -297,7 +312,7 @@ func (m *Mysql) ensureVersionTable() error {
297
312
// check if migration table exists
298
313
var result string
299
314
query := `SHOW TABLES LIKE "` + m .config .MigrationsTable + `"`
300
- if err := m .db . QueryRow ( query ).Scan (& result ); err != nil {
315
+ if err := m .conn . QueryRowContext ( context . Background (), query ).Scan (& result ); err != nil {
301
316
if err != sql .ErrNoRows {
302
317
return & database.Error {OrigErr : err , Query : []byte (query )}
303
318
}
@@ -307,7 +322,7 @@ func (m *Mysql) ensureVersionTable() error {
307
322
308
323
// if not, create the empty migration table
309
324
query = "CREATE TABLE `" + m .config .MigrationsTable + "` (version bigint not null primary key, dirty boolean not null)"
310
- if _ , err := m .db . Exec ( query ); err != nil {
325
+ if _ , err := m .conn . ExecContext ( context . Background (), query ); err != nil {
311
326
return & database.Error {OrigErr : err , Query : []byte (query )}
312
327
}
313
328
return nil
0 commit comments