1 // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
3 // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
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/.
19 type mysqlStmt struct {
25 func (stmt *mysqlStmt) Close() error {
26 if stmt.mc == nil || stmt.mc.closed.IsSet() {
27 // driver.Stmt.Close can be called more than once, thus this function
28 // has to be idempotent.
29 // See also Issue #450 and golang/go#16019.
30 //errLog.Print(ErrInvalidConn)
31 return driver.ErrBadConn
34 err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
39 func (stmt *mysqlStmt) NumInput() int {
40 return stmt.paramCount
43 func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
47 func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
48 if stmt.mc.closed.IsSet() {
49 errLog.Print(ErrInvalidConn)
50 return nil, driver.ErrBadConn
53 err := stmt.writeExecutePacket(args)
55 return nil, stmt.mc.markBadConn(err)
64 resLen, err := mc.readResultSetHeaderPacket()
71 if err = mc.readUntilEOF(); err != nil {
76 if err := mc.readUntilEOF(); err != nil {
81 if err := mc.discardResults(); err != nil {
86 affectedRows: int64(mc.affectedRows),
87 insertId: int64(mc.insertId),
91 func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
92 return stmt.query(args)
95 func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
96 if stmt.mc.closed.IsSet() {
97 errLog.Print(ErrInvalidConn)
98 return nil, driver.ErrBadConn
101 err := stmt.writeExecutePacket(args)
103 return nil, stmt.mc.markBadConn(err)
109 resLen, err := mc.readResultSetHeaderPacket()
114 rows := new(binaryRows)
118 rows.rs.columns, err = mc.readColumns(resLen)
122 switch err := rows.NextResultSet(); err {
133 type converter struct{}
135 // ConvertValue mirrors the reference/default converter in database/sql/driver
136 // with _one_ exception. We support uint64 with their high bit and the default
137 // implementation does not. This function should be kept in sync with
138 // database/sql/driver defaultConverter.ConvertValue() except for that
139 // deliberate difference.
140 func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
141 if driver.IsValue(v) {
145 if vr, ok := v.(driver.Valuer); ok {
146 sv, err := callValuerValue(vr)
150 if !driver.IsValue(sv) {
151 return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
156 rv := reflect.ValueOf(v)
163 return c.ConvertValue(rv.Elem().Interface())
165 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
167 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
168 return int64(rv.Uint()), nil
172 return strconv.FormatUint(u64, 10), nil
174 return int64(u64), nil
175 case reflect.Float32, reflect.Float64:
176 return rv.Float(), nil
178 return rv.Bool(), nil
180 ek := rv.Type().Elem().Kind()
181 if ek == reflect.Uint8 {
182 return rv.Bytes(), nil
184 return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
186 return rv.String(), nil
188 return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
191 var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
193 // callValuerValue returns vr.Value(), with one exception:
194 // If vr.Value is an auto-generated method on a pointer type and the
195 // pointer is nil, it would panic at runtime in the panicwrap
196 // method. Treat it like nil instead.
198 // This is so people can implement driver.Value on value types and
199 // still use nil pointers to those types to mean nil/NULL, just like
202 // This is an exact copy of the same-named unexported function from the
203 // database/sql package.
204 func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
205 if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
207 rv.Type().Elem().Implements(valuerReflectType) {