• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-sql-driver / mysql / 3601392501

pending completion
3601392501

push

github

GitHub
update changelog for Version 1.7 (#1376)

2932 of 3584 relevant lines covered (81.81%)

1490385.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.01
/connection.go
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

9
package mysql
10

11
import (
12
        "context"
13
        "database/sql"
14
        "database/sql/driver"
15
        "encoding/json"
16
        "io"
17
        "net"
18
        "strconv"
19
        "strings"
20
        "time"
21
)
22

23
type mysqlConn struct {
24
        buf              buffer
25
        netConn          net.Conn
26
        rawConn          net.Conn // underlying connection when netConn is TLS connection.
27
        affectedRows     uint64
28
        insertId         uint64
29
        cfg              *Config
30
        maxAllowedPacket int
31
        maxWriteSize     int
32
        writeTimeout     time.Duration
33
        flags            clientFlag
34
        status           statusFlag
35
        sequence         uint8
36
        parseTime        bool
37
        reset            bool // set when the Go SQL package calls ResetSession
38

39
        // for context support (Go 1.8+)
40
        watching bool
41
        watcher  chan<- context.Context
42
        closech  chan struct{}
43
        finished chan<- struct{}
44
        canceled atomicError // set non-nil if conn is canceled
45
        closed   atomicBool  // set when conn is closed, before closech is closed
46
}
47

48
// Handles parameters set in DSN after the connection is established
49
func (mc *mysqlConn) handleParams() (err error) {
10,649✔
50
        var cmdSet strings.Builder
10,649✔
51
        for param, val := range mc.cfg.Params {
11,486✔
52
                switch param {
837✔
53
                // Charset: character_set_connection, character_set_client, character_set_results
54
                case "charset":
513✔
55
                        charsets := strings.Split(val, ",")
513✔
56
                        for i := range charsets {
1,107✔
57
                                // ignore errors here - a charset may not exist
594✔
58
                                err = mc.exec("SET NAMES " + charsets[i])
594✔
59
                                if err == nil {
918✔
60
                                        break
324✔
61
                                }
62
                        }
63
                        if err != nil {
702✔
64
                                return
189✔
65
                        }
189✔
66

67
                // Other system vars accumulated in a single SET command
68
                default:
324✔
69
                        if cmdSet.Len() == 0 {
648✔
70
                                // Heuristic: 29 chars for each other key=value to reduce reallocations
324✔
71
                                cmdSet.Grow(4 + len(param) + 1 + len(val) + 30*(len(mc.cfg.Params)-1))
324✔
72
                                cmdSet.WriteString("SET ")
324✔
73
                        } else {
324✔
74
                                cmdSet.WriteByte(',')
×
75
                        }
×
76
                        cmdSet.WriteString(param)
324✔
77
                        cmdSet.WriteByte('=')
324✔
78
                        cmdSet.WriteString(val)
324✔
79
                }
80
        }
81

82
        if cmdSet.Len() > 0 {
10,784✔
83
                err = mc.exec(cmdSet.String())
324✔
84
                if err != nil {
324✔
85
                        return
×
86
                }
×
87
        }
88

89
        return
10,460✔
90
}
91

92
func (mc *mysqlConn) markBadConn(err error) error {
834✔
93
        if mc == nil {
834✔
94
                return err
×
95
        }
×
96
        if err != errBadConnNoWrite {
1,641✔
97
                return err
807✔
98
        }
807✔
99
        return driver.ErrBadConn
27✔
100
}
101

102
func (mc *mysqlConn) Begin() (driver.Tx, error) {
×
103
        return mc.begin(false)
×
104
}
×
105

106
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
2,592✔
107
        if mc.closed.Load() {
2,592✔
108
                errLog.Print(ErrInvalidConn)
×
109
                return nil, driver.ErrBadConn
×
110
        }
×
111
        var q string
2,592✔
112
        if readOnly {
2,673✔
113
                q = "START TRANSACTION READ ONLY"
81✔
114
        } else {
2,592✔
115
                q = "START TRANSACTION"
2,511✔
116
        }
2,511✔
117
        err := mc.exec(q)
2,592✔
118
        if err == nil {
5,123✔
119
                return &mysqlTx{mc}, err
2,531✔
120
        }
2,531✔
121
        return nil, mc.markBadConn(err)
60✔
122
}
123

124
func (mc *mysqlConn) Close() (err error) {
10,872✔
125
        // Makes Close idempotent
10,872✔
126
        if !mc.closed.Load() {
19,524✔
127
                err = mc.writeCommandPacket(comQuit)
8,652✔
128
        }
8,652✔
129

130
        mc.cleanup()
10,872✔
131

10,872✔
132
        return
10,872✔
133
}
134

135
// Closes the network connection and unsets internal variables. Do not call this
136
// function after successfully authentication, call Close instead. This function
137
// is called before auth or on auth failure because MySQL will have already
138
// closed the network connection.
139
func (mc *mysqlConn) cleanup() {
13,179✔
140
        if mc.closed.Swap(true) {
15,426✔
141
                return
2,247✔
142
        }
2,247✔
143

144
        // Makes cleanup idempotent
145
        close(mc.closech)
10,932✔
146
        if mc.netConn == nil {
10,986✔
147
                return
54✔
148
        }
54✔
149
        if err := mc.netConn.Close(); err != nil {
10,877✔
150
                errLog.Print(err)
×
151
        }
×
152
}
153

154
func (mc *mysqlConn) error() error {
26,721✔
155
        if mc.closed.Load() {
28,385✔
156
                if err := mc.canceled.Value(); err != nil {
3,328✔
157
                        return err
1,664✔
158
                }
1,664✔
159
                return ErrInvalidConn
×
160
        }
161
        return nil
25,057✔
162
}
163

164
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
4,968✔
165
        if mc.closed.Load() {
4,968✔
166
                errLog.Print(ErrInvalidConn)
×
167
                return nil, driver.ErrBadConn
×
168
        }
×
169
        // Send command
170
        err := mc.writeCommandPacketStr(comStmtPrepare, query)
4,968✔
171
        if err != nil {
4,968✔
172
                // STMT_PREPARE is safe to retry.  So we can return ErrBadConn here.
×
173
                errLog.Print(err)
×
174
                return nil, driver.ErrBadConn
×
175
        }
×
176

177
        stmt := &mysqlStmt{
4,968✔
178
                mc: mc,
4,968✔
179
        }
4,968✔
180

4,968✔
181
        // Read Result
4,968✔
182
        columnCount, err := stmt.readPrepareResultPacket()
4,968✔
183
        if err == nil {
9,936✔
184
                if stmt.paramCount > 0 {
9,288✔
185
                        if err = mc.readUntilEOF(); err != nil {
4,320✔
186
                                return nil, err
×
187
                        }
×
188
                }
189

190
                if columnCount > 0 {
7,425✔
191
                        err = mc.readUntilEOF()
2,457✔
192
                }
2,457✔
193
        }
194

195
        return stmt, err
4,968✔
196
}
197

198
func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {
2,187✔
199
        // Number of ? should be same to len(args)
2,187✔
200
        if strings.Count(query, "?") != len(args) {
2,241✔
201
                return "", driver.ErrSkip
54✔
202
        }
54✔
203

204
        buf, err := mc.buf.takeCompleteBuffer()
2,133✔
205
        if err != nil {
2,133✔
206
                // can not take the buffer. Something must be wrong with the connection
×
207
                errLog.Print(err)
×
208
                return "", ErrInvalidConn
×
209
        }
×
210
        buf = buf[:0]
2,133✔
211
        argPos := 0
2,133✔
212

2,133✔
213
        for i := 0; i < len(query); i++ {
6,210✔
214
                q := strings.IndexByte(query[i:], '?')
4,077✔
215
                if q == -1 {
5,724✔
216
                        buf = append(buf, query[i:]...)
1,647✔
217
                        break
1,647✔
218
                }
219
                buf = append(buf, query[i:i+q]...)
2,430✔
220
                i += q
2,430✔
221

2,430✔
222
                arg := args[argPos]
2,430✔
223
                argPos++
2,430✔
224

2,430✔
225
                if arg == nil {
2,511✔
226
                        buf = append(buf, "NULL"...)
81✔
227
                        continue
81✔
228
                }
229

230
                switch v := arg.(type) {
2,349✔
231
                case int64:
702✔
232
                        buf = strconv.AppendInt(buf, v, 10)
702✔
233
                case uint64:
27✔
234
                        // Handle uint64 explicitly because our custom ConvertValue emits unsigned values
27✔
235
                        buf = strconv.AppendUint(buf, v, 10)
27✔
236
                case float64:
54✔
237
                        buf = strconv.AppendFloat(buf, v, 'g', -1, 64)
54✔
238
                case bool:
81✔
239
                        if v {
108✔
240
                                buf = append(buf, '1')
27✔
241
                        } else {
81✔
242
                                buf = append(buf, '0')
54✔
243
                        }
54✔
244
                case time.Time:
324✔
245
                        if v.IsZero() {
378✔
246
                                buf = append(buf, "'0000-00-00'"...)
54✔
247
                        } else {
324✔
248
                                buf = append(buf, '\'')
270✔
249
                                buf, err = appendDateTime(buf, v.In(mc.cfg.Loc))
270✔
250
                                if err != nil {
270✔
251
                                        return "", err
×
252
                                }
×
253
                                buf = append(buf, '\'')
270✔
254
                        }
255
                case json.RawMessage:
81✔
256
                        buf = append(buf, '\'')
81✔
257
                        if mc.status&statusNoBackslashEscapes == 0 {
162✔
258
                                buf = escapeBytesBackslash(buf, v)
81✔
259
                        } else {
81✔
260
                                buf = escapeBytesQuotes(buf, v)
×
261
                        }
×
262
                        buf = append(buf, '\'')
81✔
263
                case []byte:
135✔
264
                        if v == nil {
189✔
265
                                buf = append(buf, "NULL"...)
54✔
266
                        } else {
135✔
267
                                buf = append(buf, "_binary'"...)
81✔
268
                                if mc.status&statusNoBackslashEscapes == 0 {
162✔
269
                                        buf = escapeBytesBackslash(buf, v)
81✔
270
                                } else {
81✔
271
                                        buf = escapeBytesQuotes(buf, v)
×
272
                                }
×
273
                                buf = append(buf, '\'')
81✔
274
                        }
275
                case string:
945✔
276
                        buf = append(buf, '\'')
945✔
277
                        if mc.status&statusNoBackslashEscapes == 0 {
1,809✔
278
                                buf = escapeStringBackslash(buf, v)
864✔
279
                        } else {
945✔
280
                                buf = escapeStringQuotes(buf, v)
81✔
281
                        }
81✔
282
                        buf = append(buf, '\'')
945✔
283
                default:
×
284
                        return "", driver.ErrSkip
×
285
                }
286

287
                if len(buf)+4 > mc.maxAllowedPacket {
2,376✔
288
                        return "", driver.ErrSkip
27✔
289
                }
27✔
290
        }
291
        if argPos != len(args) {
2,106✔
292
                return "", driver.ErrSkip
×
293
        }
×
294
        return string(buf), nil
2,106✔
295
}
296

297
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
445,706✔
298
        if mc.closed.Load() {
445,706✔
299
                errLog.Print(ErrInvalidConn)
×
300
                return nil, driver.ErrBadConn
×
301
        }
×
302
        if len(args) != 0 {
449,013✔
303
                if !mc.cfg.InterpolateParams {
5,535✔
304
                        return nil, driver.ErrSkip
2,214✔
305
                }
2,214✔
306
                // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement
307
                prepared, err := mc.interpolateParams(query, args)
1,107✔
308
                if err != nil {
1,134✔
309
                        return nil, err
27✔
310
                }
27✔
311
                query = prepared
1,080✔
312
        }
313
        mc.affectedRows = 0
443,450✔
314
        mc.insertId = 0
443,450✔
315

443,450✔
316
        err := mc.exec(query)
443,450✔
317
        if err == nil {
885,532✔
318
                return &mysqlResult{
442,082✔
319
                        affectedRows: int64(mc.affectedRows),
442,082✔
320
                        insertId:     int64(mc.insertId),
442,082✔
321
                }, err
442,082✔
322
        }
442,082✔
323
        return nil, mc.markBadConn(err)
525✔
324
}
325

326
// Internal function to execute commands
327
func (mc *mysqlConn) exec(query string) error {
449,473✔
328
        // Send command
449,473✔
329
        if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
449,533✔
330
                return mc.markBadConn(err)
60✔
331
        }
60✔
332

333
        // Read Result
334
        resLen, err := mc.readResultSetHeaderPacket()
450,739✔
335
        if err != nil {
451,534✔
336
                return err
795✔
337
        }
795✔
338

339
        if resLen > 0 {
448,346✔
340
                // columns
×
341
                if err := mc.readUntilEOF(); err != nil {
×
342
                        return err
×
343
                }
×
344

345
                // rows
346
                if err := mc.readUntilEOF(); err != nil {
×
347
                        return err
×
348
                }
×
349
        }
350

351
        return mc.discardResults()
448,361✔
352
}
353

354
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
×
355
        return mc.query(query, args)
×
356
}
×
357

358
func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
11,739✔
359
        if mc.closed.Load() {
11,739✔
360
                errLog.Print(ErrInvalidConn)
×
361
                return nil, driver.ErrBadConn
×
362
        }
×
363
        if len(args) != 0 {
14,601✔
364
                if !mc.cfg.InterpolateParams {
4,779✔
365
                        return nil, driver.ErrSkip
1,917✔
366
                }
1,917✔
367
                // try client-side prepare to reduce roundtrip
368
                prepared, err := mc.interpolateParams(query, args)
945✔
369
                if err != nil {
945✔
370
                        return nil, err
×
371
                }
×
372
                query = prepared
945✔
373
        }
374
        // Send command
375
        err := mc.writeCommandPacketStr(comQuery, query)
9,822✔
376
        if err == nil {
19,644✔
377
                // Read Result
9,822✔
378
                var resLen int
9,822✔
379
                resLen, err = mc.readResultSetHeaderPacket()
9,822✔
380
                if err == nil {
19,509✔
381
                        rows := new(textRows)
9,687✔
382
                        rows.mc = mc
9,687✔
383

9,687✔
384
                        if resLen == 0 {
9,822✔
385
                                rows.rs.done = true
135✔
386

135✔
387
                                switch err := rows.NextResultSet(); err {
135✔
388
                                case nil, io.EOF:
135✔
389
                                        return rows, nil
135✔
390
                                default:
×
391
                                        return nil, err
×
392
                                }
393
                        }
394

395
                        // Columns
396
                        rows.rs.columns, err = mc.readColumns(resLen)
9,552✔
397
                        return rows, err
9,552✔
398
                }
399
        }
400
        return nil, mc.markBadConn(err)
135✔
401
}
402

403
// Gets the value of the given MySQL System Variable
404
// The returned byte slice is only valid until the next read
405
func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
81✔
406
        // Send command
81✔
407
        if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
81✔
408
                return nil, err
×
409
        }
×
410

411
        // Read Result
412
        resLen, err := mc.readResultSetHeaderPacket()
81✔
413
        if err == nil {
162✔
414
                rows := new(textRows)
81✔
415
                rows.mc = mc
81✔
416
                rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
81✔
417

81✔
418
                if resLen > 0 {
162✔
419
                        // Columns
81✔
420
                        if err := mc.readUntilEOF(); err != nil {
81✔
421
                                return nil, err
×
422
                        }
×
423
                }
424

425
                dest := make([]driver.Value, resLen)
81✔
426
                if err = rows.readRow(dest); err == nil {
162✔
427
                        return dest[0].([]byte), mc.readUntilEOF()
81✔
428
                }
81✔
429
        }
430
        return nil, err
×
431
}
432

433
// finish is called when the query has canceled.
434
func (mc *mysqlConn) cancel(err error) {
2,052✔
435
        mc.canceled.Set(err)
2,052✔
436
        mc.cleanup()
2,052✔
437
}
2,052✔
438

439
// finish is called when the query has succeeded.
440
func (mc *mysqlConn) finish() {
482,460✔
441
        if !mc.watching || mc.finished == nil {
960,463✔
442
                return
478,003✔
443
        }
478,003✔
444
        select {
4,525✔
445
        case mc.finished <- struct{}{}:
2,473✔
446
                mc.watching = false
2,473✔
447
        case <-mc.closech:
2,052✔
448
        }
449
}
450

451
// Ping implements driver.Pinger interface
452
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
546✔
453
        if mc.closed.Load() {
546✔
454
                errLog.Print(ErrInvalidConn)
×
455
                return driver.ErrBadConn
×
456
        }
×
457

458
        if err = mc.watchCancel(ctx); err != nil {
627✔
459
                return
81✔
460
        }
81✔
461
        defer mc.finish()
465✔
462

465✔
463
        if err = mc.writeCommandPacket(comPing); err != nil {
519✔
464
                return mc.markBadConn(err)
54✔
465
        }
54✔
466

467
        return mc.readResultOK()
411✔
468
}
469

470
// BeginTx implements driver.ConnBeginTx interface
471
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
2,631✔
472
        if mc.closed.Load() {
2,670✔
473
                return nil, driver.ErrBadConn
39✔
474
        }
39✔
475

476
        if err := mc.watchCancel(ctx); err != nil {
2,592✔
477
                return nil, err
×
478
        }
×
479
        defer mc.finish()
2,592✔
480

2,592✔
481
        if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
2,754✔
482
                level, err := mapIsolationLevel(opts.Isolation)
162✔
483
                if err != nil {
162✔
484
                        return nil, err
×
485
                }
×
486
                err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
162✔
487
                if err != nil {
162✔
488
                        return nil, err
×
489
                }
×
490
        }
491

492
        return mc.begin(opts.ReadOnly)
2,592✔
493
}
494

495
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
11,739✔
496
        dargs, err := namedValueToValue(args)
11,739✔
497
        if err != nil {
11,739✔
498
                return nil, err
×
499
        }
×
500

501
        if err := mc.watchCancel(ctx); err != nil {
11,739✔
502
                return nil, err
×
503
        }
×
504

505
        rows, err := mc.query(query, dargs)
11,739✔
506
        if err != nil {
13,791✔
507
                mc.finish()
2,052✔
508
                return nil, err
2,052✔
509
        }
2,052✔
510
        rows.finish = mc.finish
9,687✔
511
        return rows, err
9,687✔
512
}
513

514
func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
446,374✔
515
        dargs, err := namedValueToValue(args)
446,374✔
516
        if err != nil {
446,374✔
517
                return nil, err
×
518
        }
×
519

520
        if err := mc.watchCancel(ctx); err != nil {
446,463✔
521
                return nil, err
×
522
        }
×
523
        defer mc.finish()
445,985✔
524

445,985✔
525
        return mc.Exec(query, dargs)
445,985✔
526
}
527

528
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
4,941✔
529
        if err := mc.watchCancel(ctx); err != nil {
4,941✔
530
                return nil, err
×
531
        }
×
532

533
        stmt, err := mc.Prepare(query)
4,941✔
534
        mc.finish()
4,941✔
535
        if err != nil {
4,941✔
536
                return nil, err
×
537
        }
×
538

539
        select {
4,941✔
540
        default:
4,941✔
541
        case <-ctx.Done():
×
542
                stmt.Close()
×
543
                return nil, ctx.Err()
×
544
        }
545
        return stmt, nil
4,941✔
546
}
547

548
func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
3,402✔
549
        dargs, err := namedValueToValue(args)
3,402✔
550
        if err != nil {
3,402✔
551
                return nil, err
×
552
        }
×
553

554
        if err := stmt.mc.watchCancel(ctx); err != nil {
3,402✔
555
                return nil, err
×
556
        }
×
557

558
        rows, err := stmt.query(dargs)
3,402✔
559
        if err != nil {
3,483✔
560
                stmt.mc.finish()
81✔
561
                return nil, err
81✔
562
        }
81✔
563
        rows.finish = stmt.mc.finish
3,321✔
564
        return rows, err
3,321✔
565
}
566

567
func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
2,322✔
568
        dargs, err := namedValueToValue(args)
2,322✔
569
        if err != nil {
2,322✔
570
                return nil, err
×
571
        }
×
572

573
        if err := stmt.mc.watchCancel(ctx); err != nil {
2,322✔
574
                return nil, err
×
575
        }
×
576
        defer stmt.mc.finish()
2,322✔
577

2,322✔
578
        return stmt.Exec(dargs)
2,322✔
579
}
580

581
func (mc *mysqlConn) watchCancel(ctx context.Context) error {
482,730✔
582
        if mc.watching {
482,730✔
583
                // Reach here if canceled,
×
584
                // so the connection is already invalid
×
585
                mc.cleanup()
×
586
                return nil
×
587
        }
×
588
        // When ctx is already cancelled, don't watch it.
589
        if err := ctx.Err(); err != nil {
482,842✔
590
                return err
108✔
591
        }
108✔
592
        // When ctx is not cancellable, don't watch it.
593
        if ctx.Done() == nil {
960,621✔
594
                return nil
477,986✔
595
        }
477,986✔
596
        // When watcher is not alive, can't watch it.
597
        if mc.watcher == nil {
4,525✔
598
                return nil
×
599
        }
×
600

601
        mc.watching = true
4,525✔
602
        mc.watcher <- ctx
4,525✔
603
        return nil
4,525✔
604
}
605

606
func (mc *mysqlConn) startWatcher() {
10,876✔
607
        watcher := make(chan context.Context, 1)
10,876✔
608
        mc.watcher = watcher
10,876✔
609
        finished := make(chan struct{})
10,876✔
610
        mc.finished = finished
10,876✔
611
        go func() {
21,754✔
612
                for {
26,281✔
613
                        var ctx context.Context
15,403✔
614
                        select {
15,403✔
615
                        case ctx = <-watcher:
4,525✔
616
                        case <-mc.closech:
10,877✔
617
                                return
10,877✔
618
                        }
619

620
                        select {
4,525✔
621
                        case <-ctx.Done():
2,052✔
622
                                mc.cancel(ctx.Err())
2,052✔
623
                        case <-finished:
2,473✔
624
                        case <-mc.closech:
×
625
                                return
×
626
                        }
627
                }
628
        }()
629
}
630

631
func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
7,182✔
632
        nv.Value, err = converter{}.ConvertValue(nv.Value)
7,182✔
633
        return
7,182✔
634
}
7,182✔
635

636
// ResetSession implements driver.SessionResetter.
637
// (From Go 1.10)
638
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
26,508✔
639
        if mc.closed.Load() {
26,508✔
640
                return driver.ErrBadConn
×
641
        }
×
642
        mc.reset = true
26,508✔
643
        return nil
26,508✔
644
}
645

646
// IsValid implements driver.Validator interface
647
// (From Go 1.15)
648
func (mc *mysqlConn) IsValid() bool {
36,762✔
649
        return !mc.closed.Load()
36,762✔
650
}
36,762✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc