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

go-sql-driver / mysql / 14199606418

01 Apr 2025 03:19PM UTC coverage: 82.782% (-0.2%) from 82.959%
14199606418

Pull #1691

github

brad-defined
Transaction Commit/Rollback returns connection's cached error, if present.
Pull Request #1691: Transaction Commit/Rollback returns conn's cached error, if present

7 of 14 new or added lines in 1 file covered. (50.0%)

2 existing lines in 1 file now uncovered.

3255 of 3932 relevant lines covered (82.78%)

2434341.8 hits per line

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

77.78
/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
}
24

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

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

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

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

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

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

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

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

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

78
                // Rows
79
                if err := mc.readUntilEOF(); err != nil {
×
80
                        return nil, err
×
81
                }
×
82
        }
83

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

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

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

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

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

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

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

6,992✔
117
        if resLen > 0 {
13,984✔
118
                rows.mc = mc
6,992✔
119
                rows.rs.columns, err = mc.readColumns(resLen)
6,992✔
120
        } else {
6,992✔
121
                rows.rs.done = true
×
122

×
123
                switch err := rows.NextResultSet(); err {
×
124
                case nil, io.EOF:
×
125
                        return rows, nil
×
126
                default:
×
127
                        return nil, err
×
128
                }
129
        }
130

131
        return rows, err
6,992✔
132
}
133

134
var jsonType = reflect.TypeOf(json.RawMessage{})
135

136
type converter struct{}
137

138
// ConvertValue mirrors the reference/default converter in database/sql/driver
139
// with _one_ exception.  We support uint64 with their high bit and the default
140
// implementation does not.  This function should be kept in sync with
141
// database/sql/driver defaultConverter.ConvertValue() except for that
142
// deliberate difference.
143
func (c converter) ConvertValue(v any) (driver.Value, error) {
12,604,168✔
144
        if driver.IsValue(v) {
25,205,168✔
145
                return v, nil
12,601,000✔
146
        }
12,601,000✔
147

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

196
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
197

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