github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-sql-driver/mysql/connection.go (about) 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 "net" 14 "strconv" 15 "strings" 16 "time" 17 ) 18 19 type mysqlConn struct { 20 buf buffer 21 netConn net.Conn 22 affectedRows uint64 23 insertId uint64 24 cfg *Config 25 maxPacketAllowed int 26 maxWriteSize int 27 writeTimeout time.Duration 28 flags clientFlag 29 status statusFlag 30 sequence uint8 31 parseTime bool 32 strict bool 33 } 34 35 // Handles parameters set in DSN after the connection is established 36 func (mc *mysqlConn) handleParams() (err error) { 37 for param, val := range mc.cfg.Params { 38 switch param { 39 // Charset 40 case "charset": 41 charsets := strings.Split(val, ",") 42 for i := range charsets { 43 // ignore errors here - a charset may not exist 44 err = mc.exec("SET NAMES " + charsets[i]) 45 if err == nil { 46 break 47 } 48 } 49 if err != nil { 50 return 51 } 52 53 // System Vars 54 default: 55 err = mc.exec("SET " + param + "=" + val + "") 56 if err != nil { 57 return 58 } 59 } 60 } 61 62 return 63 } 64 65 func (mc *mysqlConn) Begin() (driver.Tx, error) { 66 if mc.netConn == nil { 67 errLog.Print(ErrInvalidConn) 68 return nil, driver.ErrBadConn 69 } 70 err := mc.exec("START TRANSACTION") 71 if err == nil { 72 return &mysqlTx{mc}, err 73 } 74 75 return nil, err 76 } 77 78 func (mc *mysqlConn) Close() (err error) { 79 // Makes Close idempotent 80 if mc.netConn != nil { 81 err = mc.writeCommandPacket(comQuit) 82 } 83 84 mc.cleanup() 85 86 return 87 } 88 89 // Closes the network connection and unsets internal variables. Do not call this 90 // function after successfully authentication, call Close instead. This function 91 // is called before auth or on auth failure because MySQL will have already 92 // closed the network connection. 93 func (mc *mysqlConn) cleanup() { 94 // Makes cleanup idempotent 95 if mc.netConn != nil { 96 if err := mc.netConn.Close(); err != nil { 97 errLog.Print(err) 98 } 99 mc.netConn = nil 100 } 101 mc.cfg = nil 102 mc.buf.nc = nil 103 } 104 105 func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { 106 if mc.netConn == nil { 107 errLog.Print(ErrInvalidConn) 108 return nil, driver.ErrBadConn 109 } 110 // Send command 111 err := mc.writeCommandPacketStr(comStmtPrepare, query) 112 if err != nil { 113 return nil, err 114 } 115 116 stmt := &mysqlStmt{ 117 mc: mc, 118 } 119 120 // Read Result 121 columnCount, err := stmt.readPrepareResultPacket() 122 if err == nil { 123 if stmt.paramCount > 0 { 124 if err = mc.readUntilEOF(); err != nil { 125 return nil, err 126 } 127 } 128 129 if columnCount > 0 { 130 err = mc.readUntilEOF() 131 } 132 } 133 134 return stmt, err 135 } 136 137 func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { 138 buf := mc.buf.takeCompleteBuffer() 139 if buf == nil { 140 // can not take the buffer. Something must be wrong with the connection 141 errLog.Print(ErrBusyBuffer) 142 return "", driver.ErrBadConn 143 } 144 buf = buf[:0] 145 argPos := 0 146 147 for i := 0; i < len(query); i++ { 148 q := strings.IndexByte(query[i:], '?') 149 if q == -1 { 150 buf = append(buf, query[i:]...) 151 break 152 } 153 buf = append(buf, query[i:i+q]...) 154 i += q 155 156 arg := args[argPos] 157 argPos++ 158 159 if arg == nil { 160 buf = append(buf, "NULL"...) 161 continue 162 } 163 164 switch v := arg.(type) { 165 case int64: 166 buf = strconv.AppendInt(buf, v, 10) 167 case float64: 168 buf = strconv.AppendFloat(buf, v, 'g', -1, 64) 169 case bool: 170 if v { 171 buf = append(buf, '1') 172 } else { 173 buf = append(buf, '0') 174 } 175 case time.Time: 176 if v.IsZero() { 177 buf = append(buf, "'0000-00-00'"...) 178 } else { 179 v := v.In(mc.cfg.Loc) 180 v = v.Add(time.Nanosecond * 500) // To round under microsecond 181 year := v.Year() 182 year100 := year / 100 183 year1 := year % 100 184 month := v.Month() 185 day := v.Day() 186 hour := v.Hour() 187 minute := v.Minute() 188 second := v.Second() 189 micro := v.Nanosecond() / 1000 190 191 buf = append(buf, []byte{ 192 '\'', 193 digits10[year100], digits01[year100], 194 digits10[year1], digits01[year1], 195 '-', 196 digits10[month], digits01[month], 197 '-', 198 digits10[day], digits01[day], 199 ' ', 200 digits10[hour], digits01[hour], 201 ':', 202 digits10[minute], digits01[minute], 203 ':', 204 digits10[second], digits01[second], 205 }...) 206 207 if micro != 0 { 208 micro10000 := micro / 10000 209 micro100 := micro / 100 % 100 210 micro1 := micro % 100 211 buf = append(buf, []byte{ 212 '.', 213 digits10[micro10000], digits01[micro10000], 214 digits10[micro100], digits01[micro100], 215 digits10[micro1], digits01[micro1], 216 }...) 217 } 218 buf = append(buf, '\'') 219 } 220 case []byte: 221 if v == nil { 222 buf = append(buf, "NULL"...) 223 } else { 224 buf = append(buf, "_binary'"...) 225 if mc.status&statusNoBackslashEscapes == 0 { 226 buf = escapeBytesBackslash(buf, v) 227 } else { 228 buf = escapeBytesQuotes(buf, v) 229 } 230 buf = append(buf, '\'') 231 } 232 case string: 233 buf = append(buf, '\'') 234 if mc.status&statusNoBackslashEscapes == 0 { 235 buf = escapeStringBackslash(buf, v) 236 } else { 237 buf = escapeStringQuotes(buf, v) 238 } 239 buf = append(buf, '\'') 240 default: 241 return "", driver.ErrSkip 242 } 243 244 if len(buf)+4 > mc.maxPacketAllowed { 245 return "", driver.ErrSkip 246 } 247 } 248 if argPos != len(args) { 249 return "", driver.ErrSkip 250 } 251 return string(buf), nil 252 } 253 254 func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { 255 if mc.netConn == nil { 256 errLog.Print(ErrInvalidConn) 257 return nil, driver.ErrBadConn 258 } 259 if len(args) != 0 { 260 if !mc.cfg.InterpolateParams { 261 return nil, driver.ErrSkip 262 } 263 // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement 264 prepared, err := mc.interpolateParams(query, args) 265 if err != nil { 266 return nil, err 267 } 268 query = prepared 269 args = nil 270 } 271 mc.affectedRows = 0 272 mc.insertId = 0 273 274 err := mc.exec(query) 275 if err == nil { 276 return &mysqlResult{ 277 affectedRows: int64(mc.affectedRows), 278 insertId: int64(mc.insertId), 279 }, err 280 } 281 return nil, err 282 } 283 284 // Internal function to execute commands 285 func (mc *mysqlConn) exec(query string) error { 286 // Send command 287 err := mc.writeCommandPacketStr(comQuery, query) 288 if err != nil { 289 return err 290 } 291 292 // Read Result 293 resLen, err := mc.readResultSetHeaderPacket() 294 if err == nil && resLen > 0 { 295 if err = mc.readUntilEOF(); err != nil { 296 return err 297 } 298 299 err = mc.readUntilEOF() 300 } 301 302 return err 303 } 304 305 func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { 306 if mc.netConn == nil { 307 errLog.Print(ErrInvalidConn) 308 return nil, driver.ErrBadConn 309 } 310 if len(args) != 0 { 311 if !mc.cfg.InterpolateParams { 312 return nil, driver.ErrSkip 313 } 314 // try client-side prepare to reduce roundtrip 315 prepared, err := mc.interpolateParams(query, args) 316 if err != nil { 317 return nil, err 318 } 319 query = prepared 320 args = nil 321 } 322 // Send command 323 err := mc.writeCommandPacketStr(comQuery, query) 324 if err == nil { 325 // Read Result 326 var resLen int 327 resLen, err = mc.readResultSetHeaderPacket() 328 if err == nil { 329 rows := new(textRows) 330 rows.mc = mc 331 332 if resLen == 0 { 333 // no columns, no more data 334 return emptyRows{}, nil 335 } 336 // Columns 337 rows.columns, err = mc.readColumns(resLen) 338 return rows, err 339 } 340 } 341 return nil, err 342 } 343 344 // Gets the value of the given MySQL System Variable 345 // The returned byte slice is only valid until the next read 346 func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { 347 // Send command 348 if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { 349 return nil, err 350 } 351 352 // Read Result 353 resLen, err := mc.readResultSetHeaderPacket() 354 if err == nil { 355 rows := new(textRows) 356 rows.mc = mc 357 rows.columns = []mysqlField{{fieldType: fieldTypeVarChar}} 358 359 if resLen > 0 { 360 // Columns 361 if err := mc.readUntilEOF(); err != nil { 362 return nil, err 363 } 364 } 365 366 dest := make([]driver.Value, resLen) 367 if err = rows.readRow(dest); err == nil { 368 return dest[0].([]byte), mc.readUntilEOF() 369 } 370 } 371 return nil, err 372 }