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  }