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

go-sql-driver / mysql / 9365321271

04 Jun 2024 10:15AM UTC coverage: 82.558% (-0.02%) from 82.579%
9365321271

Pull #1593

github

methane
log: add "filename:line" prefix by ourself (#1589)

go-sql-driver/mysql#1563 broke the filename:lineno prefix in the log
message by introducing a helper function.
This commit adds the "filename:line" prefix in the helper function
instead of log.Lshortfile option to show correct filename:lineno.

(cherry picked from commit 2f7015e5c)
Pull Request #1593: log: add "filename:line" prefix by ourself (#1589)

8 of 8 new or added lines in 1 file covered. (100.0%)

2 existing lines in 1 file now uncovered.

3143 of 3807 relevant lines covered (82.56%)

1297169.35 hits per line

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

74.59
/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
        "fmt"
17
        "io"
18
        "net"
19
        "runtime"
20
        "strconv"
21
        "strings"
22
        "time"
23
)
24

25
type mysqlConn struct {
26
        buf              buffer
27
        netConn          net.Conn
28
        rawConn          net.Conn    // underlying connection when netConn is TLS connection.
29
        result           mysqlResult // managed by clearResult() and handleOkPacket().
30
        cfg              *Config
31
        connector        *connector
32
        maxAllowedPacket int
33
        maxWriteSize     int
34
        writeTimeout     time.Duration
35
        flags            clientFlag
36
        status           statusFlag
37
        sequence         uint8
38
        parseTime        bool
39

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

49
// Helper function to call per-connection logger.
50
func (mc *mysqlConn) log(v ...any) {
534✔
51
        _, filename, lineno, ok := runtime.Caller(1)
534✔
52
        if ok {
1,068✔
53
                pos := strings.LastIndexByte(filename, '/')
534✔
54
                if pos != -1 {
1,068✔
55
                        filename = filename[pos+1:]
534✔
56
                }
534✔
57
                prefix := fmt.Sprintf("%s:%d ", filename, lineno)
534✔
58
                v = append([]any{prefix}, v...)
534✔
59
        }
60

61
        mc.cfg.Logger.Print(v...)
534✔
62
}
63

64
// Handles parameters set in DSN after the connection is established
65
func (mc *mysqlConn) handleParams() (err error) {
14,386✔
66
        var cmdSet strings.Builder
14,386✔
67

14,386✔
68
        for param, val := range mc.cfg.Params {
14,926✔
69
                switch param {
540✔
70
                // Charset: character_set_connection, character_set_client, character_set_results
71
                case "charset":
300✔
72
                        charsets := strings.Split(val, ",")
300✔
73
                        for _, cs := range charsets {
660✔
74
                                // ignore errors here - a charset may not exist
360✔
75
                                if mc.cfg.Collation != "" {
360✔
76
                                        err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation)
×
77
                                } else {
360✔
78
                                        err = mc.exec("SET NAMES " + cs)
360✔
79
                                }
360✔
80
                                if err == nil {
600✔
81
                                        break
240✔
82
                                }
83
                        }
84
                        if err != nil {
360✔
85
                                return
60✔
86
                        }
60✔
87

88
                // Other system vars accumulated in a single SET command
89
                default:
240✔
90
                        if cmdSet.Len() == 0 {
480✔
91
                                // Heuristic: 29 chars for each other key=value to reduce reallocations
240✔
92
                                cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1))
240✔
93
                                cmdSet.WriteString("SET ")
240✔
94
                        } else {
240✔
95
                                cmdSet.WriteString(", ")
×
96
                        }
×
97
                        cmdSet.WriteString(param)
240✔
98
                        cmdSet.WriteString(" = ")
240✔
99
                        cmdSet.WriteString(val)
240✔
100
                }
101
        }
102

103
        if cmdSet.Len() > 0 {
14,566✔
104
                err = mc.exec(cmdSet.String())
240✔
105
                if err != nil {
240✔
106
                        return
×
107
                }
×
108
        }
109

110
        return
14,326✔
111
}
112

113
func (mc *mysqlConn) markBadConn(err error) error {
440✔
114
        if mc == nil {
440✔
115
                return err
×
116
        }
×
117
        if err != errBadConnNoWrite {
850✔
118
                return err
410✔
119
        }
410✔
120
        return driver.ErrBadConn
30✔
121
}
122

123
func (mc *mysqlConn) Begin() (driver.Tx, error) {
×
124
        return mc.begin(false)
×
125
}
×
126

127
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
3,108✔
128
        if mc.closed.Load() {
3,108✔
129
                mc.log(ErrInvalidConn)
×
130
                return nil, driver.ErrBadConn
×
131
        }
×
132
        var q string
3,108✔
133
        if readOnly {
3,138✔
134
                q = "START TRANSACTION READ ONLY"
30✔
135
        } else {
3,108✔
136
                q = "START TRANSACTION"
3,078✔
137
        }
3,078✔
138
        err := mc.exec(q)
3,108✔
139
        if err == nil {
6,216✔
140
                return &mysqlTx{mc}, err
3,108✔
141
        }
3,108✔
142
        return nil, mc.markBadConn(err)
×
143
}
144

145
func (mc *mysqlConn) Close() (err error) {
14,446✔
146
        // Makes Close idempotent
14,446✔
147
        if !mc.closed.Load() {
25,914✔
148
                err = mc.writeCommandPacket(comQuit)
11,468✔
149
        }
11,468✔
150

151
        mc.cleanup()
14,446✔
152
        mc.clearResult()
14,446✔
153
        return
14,446✔
154
}
155

156
// Closes the network connection and unsets internal variables. Do not call this
157
// function after successfully authentication, call Close instead. This function
158
// is called before auth or on auth failure because MySQL will have already
159
// closed the network connection.
160
func (mc *mysqlConn) cleanup() {
122,299✔
161
        if mc.closed.Swap(true) {
177,356✔
162
                return
55,057✔
163
        }
55,057✔
164

165
        // Makes cleanup idempotent
166
        close(mc.closech)
67,242✔
167
        conn := mc.rawConn
67,242✔
168
        if conn == nil {
67,392✔
169
                return
150✔
170
        }
150✔
171
        if err := conn.Close(); err != nil {
67,092✔
172
                mc.log(err)
×
173
        }
×
174
        // This function can be called from multiple goroutines.
175
        // So we can not mc.clearResult() here.
176
        // Caller should do it if they are in safe goroutine.
177
}
178

179
func (mc *mysqlConn) error() error {
17,304✔
180
        if mc.closed.Load() {
18,534✔
181
                if err := mc.canceled.Value(); err != nil {
2,460✔
182
                        return err
1,230✔
183
                }
1,230✔
184
                return ErrInvalidConn
×
185
        }
186
        return nil
16,074✔
187
}
188

189
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
2,760✔
190
        if mc.closed.Load() {
2,760✔
191
                mc.log(ErrInvalidConn)
×
192
                return nil, driver.ErrBadConn
×
193
        }
×
194
        // Send command
195
        err := mc.writeCommandPacketStr(comStmtPrepare, query)
2,760✔
196
        if err != nil {
2,760✔
197
                // STMT_PREPARE is safe to retry.  So we can return ErrBadConn here.
×
198
                mc.log(err)
×
199
                return nil, driver.ErrBadConn
×
200
        }
×
201

202
        stmt := &mysqlStmt{
2,760✔
203
                mc: mc,
2,760✔
204
        }
2,760✔
205

2,760✔
206
        // Read Result
2,760✔
207
        columnCount, err := stmt.readPrepareResultPacket()
2,760✔
208
        if err == nil {
5,520✔
209
                if stmt.paramCount > 0 {
5,220✔
210
                        if err = mc.readUntilEOF(); err != nil {
2,460✔
211
                                return nil, err
×
212
                        }
×
213
                }
214

215
                if columnCount > 0 {
4,080✔
216
                        err = mc.readUntilEOF()
1,320✔
217
                }
1,320✔
218
        }
219

220
        return stmt, err
2,760✔
221
}
222

223
func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {
1,410✔
224
        // Number of ? should be same to len(args)
1,410✔
225
        if strings.Count(query, "?") != len(args) {
1,470✔
226
                return "", driver.ErrSkip
60✔
227
        }
60✔
228

229
        buf, err := mc.buf.takeCompleteBuffer()
1,350✔
230
        if err != nil {
1,350✔
231
                // can not take the buffer. Something must be wrong with the connection
×
232
                mc.log(err)
×
233
                return "", ErrInvalidConn
×
234
        }
×
235
        buf = buf[:0]
1,350✔
236
        argPos := 0
1,350✔
237

1,350✔
238
        for i := 0; i < len(query); i++ {
3,930✔
239
                q := strings.IndexByte(query[i:], '?')
2,580✔
240
                if q == -1 {
3,660✔
241
                        buf = append(buf, query[i:]...)
1,080✔
242
                        break
1,080✔
243
                }
244
                buf = append(buf, query[i:i+q]...)
1,500✔
245
                i += q
1,500✔
246

1,500✔
247
                arg := args[argPos]
1,500✔
248
                argPos++
1,500✔
249

1,500✔
250
                if arg == nil {
1,500✔
251
                        buf = append(buf, "NULL"...)
×
252
                        continue
×
253
                }
254

255
                switch v := arg.(type) {
1,500✔
256
                case int64:
300✔
257
                        buf = strconv.AppendInt(buf, v, 10)
300✔
258
                case uint64:
30✔
259
                        // Handle uint64 explicitly because our custom ConvertValue emits unsigned values
30✔
260
                        buf = strconv.AppendUint(buf, v, 10)
30✔
261
                case float64:
×
262
                        buf = strconv.AppendFloat(buf, v, 'g', -1, 64)
×
263
                case bool:
×
264
                        if v {
×
265
                                buf = append(buf, '1')
×
266
                        } else {
×
267
                                buf = append(buf, '0')
×
268
                        }
×
269
                case time.Time:
360✔
270
                        if v.IsZero() {
420✔
271
                                buf = append(buf, "'0000-00-00'"...)
60✔
272
                        } else {
360✔
273
                                buf = append(buf, '\'')
300✔
274
                                buf, err = appendDateTime(buf, v.In(mc.cfg.Loc), mc.cfg.timeTruncate)
300✔
275
                                if err != nil {
300✔
276
                                        return "", err
×
277
                                }
×
278
                                buf = append(buf, '\'')
300✔
279
                        }
280
                case json.RawMessage:
30✔
281
                        buf = append(buf, '\'')
30✔
282
                        if mc.status&statusNoBackslashEscapes == 0 {
60✔
283
                                buf = escapeBytesBackslash(buf, v)
30✔
284
                        } else {
30✔
285
                                buf = escapeBytesQuotes(buf, v)
×
286
                        }
×
287
                        buf = append(buf, '\'')
30✔
288
                case []byte:
×
289
                        if v == nil {
×
290
                                buf = append(buf, "NULL"...)
×
291
                        } else {
×
292
                                buf = append(buf, "_binary'"...)
×
293
                                if mc.status&statusNoBackslashEscapes == 0 {
×
294
                                        buf = escapeBytesBackslash(buf, v)
×
295
                                } else {
×
296
                                        buf = escapeBytesQuotes(buf, v)
×
297
                                }
×
298
                                buf = append(buf, '\'')
×
299
                        }
300
                case string:
780✔
301
                        buf = append(buf, '\'')
780✔
302
                        if mc.status&statusNoBackslashEscapes == 0 {
1,470✔
303
                                buf = escapeStringBackslash(buf, v)
690✔
304
                        } else {
780✔
305
                                buf = escapeStringQuotes(buf, v)
90✔
306
                        }
90✔
307
                        buf = append(buf, '\'')
780✔
308
                default:
×
309
                        return "", driver.ErrSkip
×
310
                }
311

312
                if len(buf)+4 > mc.maxAllowedPacket {
1,530✔
313
                        return "", driver.ErrSkip
30✔
314
                }
30✔
315
        }
316
        if argPos != len(args) {
1,320✔
317
                return "", driver.ErrSkip
×
318
        }
×
319
        return string(buf), nil
1,320✔
320
}
321

322
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
13,158✔
323
        if mc.closed.Load() {
13,158✔
324
                mc.log(ErrInvalidConn)
×
325
                return nil, driver.ErrBadConn
×
326
        }
×
327
        if len(args) != 0 {
14,838✔
328
                if !mc.cfg.InterpolateParams {
2,910✔
329
                        return nil, driver.ErrSkip
1,230✔
330
                }
1,230✔
331
                // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement
332
                prepared, err := mc.interpolateParams(query, args)
450✔
333
                if err != nil {
480✔
334
                        return nil, err
30✔
335
                }
30✔
336
                query = prepared
420✔
337
        }
338

339
        err := mc.exec(query)
11,898✔
340
        if err == nil {
23,484✔
341
                copied := mc.result
11,586✔
342
                return &copied, err
11,586✔
343
        }
11,586✔
344
        return nil, mc.markBadConn(err)
312✔
345
}
346

347
// Internal function to execute commands
348
func (mc *mysqlConn) exec(query string) error {
18,762✔
349
        handleOk := mc.clearResult()
18,762✔
350
        // Send command
18,762✔
351
        if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
18,762✔
352
                return mc.markBadConn(err)
×
353
        }
×
354

355
        // Read Result
356
        resLen, err := handleOk.readResultSetHeaderPacket()
18,762✔
357
        if err != nil {
19,194✔
358
                return err
432✔
359
        }
432✔
360

361
        if resLen > 0 {
18,330✔
362
                // columns
×
363
                if err := mc.readUntilEOF(); err != nil {
×
364
                        return err
×
365
                }
×
366

367
                // rows
368
                if err := mc.readUntilEOF(); err != nil {
×
369
                        return err
×
370
                }
×
371
        }
372

373
        return handleOk.discardResults()
18,330✔
374
}
375

376
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
120✔
377
        return mc.query(query, args)
120✔
378
}
120✔
379

380
func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
7,410✔
381
        handleOk := mc.clearResult()
7,410✔
382

7,410✔
383
        if mc.closed.Load() {
7,410✔
384
                mc.log(ErrInvalidConn)
×
385
                return nil, driver.ErrBadConn
×
386
        }
×
387
        if len(args) != 0 {
9,330✔
388
                if !mc.cfg.InterpolateParams {
3,030✔
389
                        return nil, driver.ErrSkip
1,110✔
390
                }
1,110✔
391
                // try client-side prepare to reduce roundtrip
392
                prepared, err := mc.interpolateParams(query, args)
810✔
393
                if err != nil {
810✔
394
                        return nil, err
×
395
                }
×
396
                query = prepared
810✔
397
        }
398
        // Send command
399
        err := mc.writeCommandPacketStr(comQuery, query)
6,300✔
400
        if err == nil {
12,600✔
401
                // Read Result
6,300✔
402
                var resLen int
6,300✔
403
                resLen, err = handleOk.readResultSetHeaderPacket()
6,300✔
404
                if err == nil {
12,534✔
405
                        rows := new(textRows)
6,234✔
406
                        rows.mc = mc
6,234✔
407

6,234✔
408
                        if resLen == 0 {
6,384✔
409
                                rows.rs.done = true
150✔
410

150✔
411
                                switch err := rows.NextResultSet(); err {
150✔
412
                                case nil, io.EOF:
150✔
413
                                        return rows, nil
150✔
414
                                default:
×
415
                                        return nil, err
×
416
                                }
417
                        }
418

419
                        // Columns
420
                        rows.rs.columns, err = mc.readColumns(resLen)
6,084✔
421
                        return rows, err
6,084✔
422
                }
423
        }
424
        return nil, mc.markBadConn(err)
66✔
425
}
426

427
// Gets the value of the given MySQL System Variable
428
// The returned byte slice is only valid until the next read
429
func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
60✔
430
        // Send command
60✔
431
        handleOk := mc.clearResult()
60✔
432
        if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
60✔
433
                return nil, err
×
434
        }
×
435

436
        // Read Result
437
        resLen, err := handleOk.readResultSetHeaderPacket()
60✔
438
        if err == nil {
120✔
439
                rows := new(textRows)
60✔
440
                rows.mc = mc
60✔
441
                rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
60✔
442

60✔
443
                if resLen > 0 {
120✔
444
                        // Columns
60✔
445
                        if err := mc.readUntilEOF(); err != nil {
60✔
446
                                return nil, err
×
447
                        }
×
448
                }
449

450
                dest := make([]driver.Value, resLen)
60✔
451
                if err = rows.readRow(dest); err == nil {
120✔
452
                        return dest[0].([]byte), mc.readUntilEOF()
60✔
453
                }
60✔
454
        }
455
        return nil, err
×
456
}
457

458
// finish is called when the query has canceled.
459
func (mc *mysqlConn) cancel(err error) {
54,937✔
460
        mc.canceled.Set(err)
54,937✔
461
        mc.cleanup()
54,937✔
462
}
54,937✔
463

464
// finish is called when the query has succeeded.
465
func (mc *mysqlConn) finish() {
102,216✔
466
        if !mc.watching || mc.finished == nil {
137,546✔
467
                return
35,330✔
468
        }
35,330✔
469
        select {
66,886✔
470
        case mc.finished <- struct{}{}:
11,949✔
471
                mc.watching = false
11,949✔
472
        case <-mc.closech:
54,937✔
473
        }
474
}
475

476
// Ping implements driver.Pinger interface
477
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
6,767✔
478
        if mc.closed.Load() {
7,070✔
479
                mc.log(ErrInvalidConn)
303✔
480
                return driver.ErrBadConn
303✔
481
        }
303✔
482

483
        if err = mc.watchCancel(ctx); err != nil {
6,580✔
484
                return
116✔
485
        }
116✔
486
        defer mc.finish()
6,348✔
487

6,348✔
488
        handleOk := mc.clearResult()
6,348✔
489
        if err = mc.writeCommandPacket(comPing); err != nil {
6,410✔
490
                return mc.markBadConn(err)
62✔
491
        }
62✔
492

493
        return handleOk.readResultOK()
6,286✔
494
}
495

496
// BeginTx implements driver.ConnBeginTx interface
497
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
3,120✔
498
        if mc.closed.Load() {
3,132✔
499
                return nil, driver.ErrBadConn
12✔
500
        }
12✔
501

502
        if err := mc.watchCancel(ctx); err != nil {
3,108✔
503
                return nil, err
×
504
        }
×
505
        defer mc.finish()
3,108✔
506

3,108✔
507
        if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
3,168✔
508
                level, err := mapIsolationLevel(opts.Isolation)
60✔
509
                if err != nil {
60✔
510
                        return nil, err
×
511
                }
×
512
                err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
60✔
513
                if err != nil {
60✔
514
                        return nil, err
×
515
                }
×
516
        }
517

518
        return mc.begin(opts.ReadOnly)
3,108✔
519
}
520

521
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
7,290✔
522
        dargs, err := namedValueToValue(args)
7,290✔
523
        if err != nil {
7,290✔
524
                return nil, err
×
525
        }
×
526

527
        if err := mc.watchCancel(ctx); err != nil {
7,290✔
528
                return nil, err
×
529
        }
×
530

531
        rows, err := mc.query(query, dargs)
7,290✔
532
        if err != nil {
8,466✔
533
                mc.finish()
1,176✔
534
                return nil, err
1,176✔
535
        }
1,176✔
536
        rows.finish = mc.finish
6,114✔
537
        return rows, err
6,114✔
538
}
539

540
func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
13,128✔
541
        dargs, err := namedValueToValue(args)
13,128✔
542
        if err != nil {
13,128✔
543
                return nil, err
×
544
        }
×
545

546
        if err := mc.watchCancel(ctx); err != nil {
13,128✔
547
                return nil, err
×
548
        }
×
549
        defer mc.finish()
13,128✔
550

13,128✔
551
        return mc.Exec(query, dargs)
13,128✔
552
}
553

554
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
2,730✔
555
        if err := mc.watchCancel(ctx); err != nil {
2,730✔
556
                return nil, err
×
557
        }
×
558

559
        stmt, err := mc.Prepare(query)
2,730✔
560
        mc.finish()
2,730✔
561
        if err != nil {
2,730✔
562
                return nil, err
×
563
        }
×
564

565
        select {
2,730✔
566
        default:
2,730✔
567
        case <-ctx.Done():
×
568
                stmt.Close()
×
569
                return nil, ctx.Err()
×
570
        }
571
        return stmt, nil
2,730✔
572
}
573

574
func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
1,800✔
575
        dargs, err := namedValueToValue(args)
1,800✔
576
        if err != nil {
1,800✔
577
                return nil, err
×
578
        }
×
579

580
        if err := stmt.mc.watchCancel(ctx); err != nil {
1,800✔
581
                return nil, err
×
582
        }
×
583

584
        rows, err := stmt.query(dargs)
1,800✔
585
        if err != nil {
1,830✔
586
                stmt.mc.finish()
30✔
587
                return nil, err
30✔
588
        }
30✔
589
        rows.finish = stmt.mc.finish
1,770✔
590
        return rows, err
1,770✔
591
}
592

593
func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
1,290✔
594
        dargs, err := namedValueToValue(args)
1,290✔
595
        if err != nil {
1,290✔
596
                return nil, err
×
597
        }
×
598

599
        if err := stmt.mc.watchCancel(ctx); err != nil {
1,290✔
600
                return nil, err
×
601
        }
×
602
        defer stmt.mc.finish()
1,290✔
603

1,290✔
604
        return stmt.Exec(dargs)
1,290✔
605
}
606

607
func (mc *mysqlConn) watchCancel(ctx context.Context) error {
103,052✔
608
        if mc.watching {
103,052✔
609
                // Reach here if canceled,
×
610
                // so the connection is already invalid
×
611
                mc.cleanup()
×
612
                return nil
×
613
        }
×
614
        // When ctx is already cancelled, don't watch it.
615
        if err := ctx.Err(); err != nil {
103,858✔
616
                return err
806✔
617
        }
806✔
618
        // When ctx is not cancellable, don't watch it.
619
        if ctx.Done() == nil {
137,606✔
620
                return nil
35,360✔
621
        }
35,360✔
622
        // When watcher is not alive, can't watch it.
623
        if mc.watcher == nil {
66,886✔
624
                return nil
×
625
        }
×
626

627
        mc.watching = true
66,886✔
628
        mc.watcher <- ctx
66,886✔
629
        return nil
66,886✔
630
}
631

632
func (mc *mysqlConn) startWatcher() {
67,272✔
633
        watcher := make(chan context.Context, 1)
67,272✔
634
        mc.watcher = watcher
67,272✔
635
        finished := make(chan struct{})
67,272✔
636
        mc.finished = finished
67,272✔
637
        go func() {
134,544✔
638
                for {
201,430✔
639
                        var ctx context.Context
134,158✔
640
                        select {
134,158✔
641
                        case ctx = <-watcher:
66,886✔
642
                        case <-mc.closech:
67,122✔
643
                                return
67,122✔
644
                        }
645

646
                        select {
66,886✔
647
                        case <-ctx.Done():
54,937✔
648
                                mc.cancel(ctx.Err())
54,937✔
649
                        case <-finished:
11,949✔
UNCOV
650
                        case <-mc.closech:
×
UNCOV
651
                                return
×
652
                        }
653
                }
654
        }()
655
}
656

657
func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
4,110✔
658
        nv.Value, err = converter{}.ConvertValue(nv.Value)
4,110✔
659
        return
4,110✔
660
}
4,110✔
661

662
// ResetSession implements driver.SessionResetter.
663
// (From Go 1.10)
664
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
13,876✔
665
        if mc.closed.Load() {
13,876✔
666
                return driver.ErrBadConn
×
667
        }
×
668

669
        // Perform a stale connection check. We only perform this check for
670
        // the first query on a connection that has been checked out of the
671
        // connection pool: a fresh connection from the pool is more likely
672
        // to be stale, and it has not performed any previous writes that
673
        // could cause data corruption, so it's safe to return ErrBadConn
674
        // if the check fails.
675
        if mc.cfg.CheckConnLiveness {
27,752✔
676
                conn := mc.netConn
13,876✔
677
                if mc.rawConn != nil {
27,752✔
678
                        conn = mc.rawConn
13,876✔
679
                }
13,876✔
680
                var err error
13,876✔
681
                if mc.cfg.ReadTimeout != 0 {
13,876✔
682
                        err = conn.SetReadDeadline(time.Now().Add(mc.cfg.ReadTimeout))
×
683
                }
×
684
                if err == nil {
27,752✔
685
                        err = connCheck(conn)
13,876✔
686
                }
13,876✔
687
                if err != nil {
13,897✔
688
                        mc.log("closing bad idle connection: ", err)
21✔
689
                        return driver.ErrBadConn
21✔
690
                }
21✔
691
        }
692

693
        return nil
13,855✔
694
}
695

696
// IsValid implements driver.Validator interface
697
// (From Go 1.15)
698
func (mc *mysqlConn) IsValid() bool {
27,686✔
699
        return !mc.closed.Load()
27,686✔
700
}
27,686✔
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