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

go-sql-driver / mysql / 14224124444

02 Apr 2025 03:54PM UTC coverage: 83.05% (+0.09%) from 82.959%
14224124444

Pull #1692

github

rusher
Implement clientDeprecateEOF flag. (not real performance improvement, but will permit further enhancement)
Pull Request #1692: MariaDB metadata skipping + test stability improvement

170 of 203 new or added lines in 6 files covered. (83.74%)

3 existing lines in 1 file now uncovered.

3322 of 4000 relevant lines covered (83.05%)

2184247.27 hits per line

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

75.69
/statement.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
        "database/sql/driver"
13
        "encoding/json"
14
        "fmt"
15
        "io"
16
        "reflect"
17
)
18

19
type mysqlStmt struct {
20
        mc         *mysqlConn
21
        id         uint32
22
        paramCount int
23
        columns    []mysqlField
24
}
25

26
func (stmt *mysqlStmt) Close() error {
8,400✔
27
        if stmt.mc == nil || stmt.mc.closed.Load() {
8,464✔
28
                // driver.Stmt.Close could be called more than once, thus this function
64✔
29
                // had to be idempotent. See also Issue #450 and golang/go#16019.
64✔
30
                // This bug has been fixed in Go 1.8.
64✔
31
                // https://github.com/golang/go/commit/90b8a0ca2d0b565c7c7199ffcf77b15ea6b6db3a
64✔
32
                // But we keep this function idempotent because it is safer.
64✔
33
                return nil
64✔
34
        }
64✔
35

36
        err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
8,336✔
37
        stmt.mc = nil
8,336✔
38
        return err
8,336✔
39
}
40

41
func (stmt *mysqlStmt) NumInput() int {
8,848✔
42
        return stmt.paramCount
8,848✔
43
}
8,848✔
44

45
func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
×
46
        return converter{}
×
47
}
×
48

49
func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) {
12,591,440✔
50
        nv.Value, err = converter{}.ConvertValue(nv.Value)
12,591,440✔
51
        return
12,591,440✔
52
}
12,591,440✔
53

54
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
1,888✔
55
        if stmt.mc.closed.Load() {
1,920✔
56
                return nil, driver.ErrBadConn
32✔
57
        }
32✔
58
        // Send command
59
        err := stmt.writeExecutePacket(args)
1,856✔
60
        if err != nil {
1,856✔
61
                return nil, stmt.mc.markBadConn(err)
×
62
        }
×
63

64
        mc := stmt.mc
1,856✔
65
        handleOk := stmt.mc.clearResult()
1,856✔
66

1,856✔
67
        // Read Result
1,856✔
68
        resLen, _, err := handleOk.readResultSetHeaderPacket()
1,856✔
69
        if err != nil {
1,888✔
70
                return nil, err
32✔
71
        }
32✔
72

73
        if resLen > 0 {
1,824✔
74
                // Columns
×
NEW
75
                if err = mc.skipColumns(resLen); err != nil {
×
76
                        return nil, err
×
77
                }
×
78

79
                // Rows
NEW
80
                if err = mc.skipResultSetRows(); err != nil {
×
81
                        return nil, err
×
82
                }
×
83
        }
84

85
        if err := handleOk.discardResults(); err != nil {
1,824✔
86
                return nil, err
×
87
        }
×
88

89
        copied := mc.result
1,824✔
90
        return &copied, nil
1,824✔
91
}
92

93
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
×
94
        return stmt.query(args)
×
95
}
×
96

97
func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
7,024✔
98
        if stmt.mc.closed.Load() {
7,024✔
99
                return nil, driver.ErrBadConn
×
100
        }
×
101
        // Send command
102
        err := stmt.writeExecutePacket(args)
7,024✔
103
        if err != nil {
7,024✔
104
                return nil, stmt.mc.markBadConn(err)
×
105
        }
×
106

107
        mc := stmt.mc
7,024✔
108

7,024✔
109
        // Read Result
7,024✔
110
        handleOk := stmt.mc.clearResult()
7,024✔
111
        resLen, metadataFollows, err := handleOk.readResultSetHeaderPacket()
7,024✔
112
        if err != nil {
7,056✔
113
                return nil, err
32✔
114
        }
32✔
115

116
        rows := new(binaryRows)
6,992✔
117

6,992✔
118
        if resLen > 0 {
13,984✔
119
                rows.mc = mc
6,992✔
120
                if metadataFollows {
10,624✔
121
                        if rows.rs.columns, err = mc.readColumns(resLen); err != nil {
3,632✔
NEW
122
                                return nil, err
×
NEW
123
                        }
×
124
                        stmt.columns = rows.rs.columns
3,632✔
125
                } else {
3,360✔
126
                        if err = mc.skipEof(); err != nil {
3,360✔
NEW
127
                                return nil, err
×
NEW
128
                        }
×
129
                        rows.rs.columns = stmt.columns
3,360✔
130
                }
131
        } else {
×
132
                rows.rs.done = true
×
133

×
134
                switch err := rows.NextResultSet(); err {
×
135
                case nil, io.EOF:
×
136
                        return rows, nil
×
137
                default:
×
138
                        return nil, err
×
139
                }
140
        }
141

142
        return rows, err
6,992✔
143
}
144

145
var jsonType = reflect.TypeOf(json.RawMessage{})
146

147
type converter struct{}
148

149
// ConvertValue mirrors the reference/default converter in database/sql/driver
150
// with _one_ exception.  We support uint64 with their high bit and the default
151
// implementation does not.  This function should be kept in sync with
152
// database/sql/driver defaultConverter.ConvertValue() except for that
153
// deliberate difference.
154
func (c converter) ConvertValue(v any) (driver.Value, error) {
12,604,168✔
155
        if driver.IsValue(v) {
25,205,168✔
156
                return v, nil
12,601,000✔
157
        }
12,601,000✔
158

159
        if vr, ok := v.(driver.Valuer); ok {
3,424✔
160
                sv, err := callValuerValue(vr)
256✔
161
                if err != nil {
288✔
162
                        return nil, err
32✔
163
                }
32✔
164
                if driver.IsValue(sv) {
416✔
165
                        return sv, nil
192✔
166
                }
192✔
167
                // A value returned from the Valuer interface can be "a type handled by
168
                // a database driver's NamedValueChecker interface" so we should accept
169
                // uint64 here as well.
170
                if u, ok := sv.(uint64); ok {
64✔
171
                        return u, nil
32✔
172
                }
32✔
173
                return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
×
174
        }
175
        rv := reflect.ValueOf(v)
2,912✔
176
        switch rv.Kind() {
2,912✔
177
        case reflect.Ptr:
32✔
178
                // indirect pointers
32✔
179
                if rv.IsNil() {
32✔
180
                        return nil, nil
×
181
                } else {
32✔
182
                        return c.ConvertValue(rv.Elem().Interface())
32✔
183
                }
32✔
184
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2,080✔
185
                return rv.Int(), nil
2,080✔
186
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
352✔
187
                return rv.Uint(), nil
352✔
188
        case reflect.Float32, reflect.Float64:
128✔
189
                return rv.Float(), nil
128✔
190
        case reflect.Bool:
32✔
191
                return rv.Bool(), nil
32✔
192
        case reflect.Slice:
224✔
193
                switch t := rv.Type(); {
224✔
194
                case t == jsonType:
160✔
195
                        return v, nil
160✔
196
                case t.Elem().Kind() == reflect.Uint8:
32✔
197
                        return rv.Bytes(), nil
32✔
198
                default:
32✔
199
                        return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind())
32✔
200
                }
201
        case reflect.String:
32✔
202
                return rv.String(), nil
32✔
203
        }
204
        return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
32✔
205
}
206

207
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
208

209
// callValuerValue returns vr.Value(), with one exception:
210
// If vr.Value is an auto-generated method on a pointer type and the
211
// pointer is nil, it would panic at runtime in the panicwrap
212
// method. Treat it like nil instead.
213
//
214
// This is so people can implement driver.Value on value types and
215
// still use nil pointers to those types to mean nil/NULL, just like
216
// string/*string.
217
//
218
// This is an exact copy of the same-named unexported function from the
219
// database/sql package.
220
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
256✔
221
        if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
256✔
222
                rv.IsNil() &&
256✔
223
                rv.Type().Elem().Implements(valuerReflectType) {
320✔
224
                return nil, nil
64✔
225
        }
64✔
226
        return vr.Value()
192✔
227
}
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

© 2026 Coveralls, Inc