github.com/eden-framework/sqlx@v0.0.2/mysqlconnector/interpolate_params.go (about)

     1  package mysqlconnector
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"errors"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
    12  	dargs := make([]driver.Value, len(named))
    13  	for n, param := range named {
    14  		if len(param.Name) > 0 {
    15  			// TODO: support the use of Named Parameters #561
    16  			return nil, errors.New("mysql: driver does not support the use of Named Parameters")
    17  		}
    18  		dargs[n] = param.Value
    19  	}
    20  	return dargs, nil
    21  }
    22  
    23  func interpolateParams(query string, args []driver.Value, loc *time.Location, maxAllowedPacket int) (string, error) {
    24  	if strings.Count(query, "?") != len(args) {
    25  		return "", driver.ErrSkip
    26  	}
    27  
    28  	buf := make([]byte, 0)
    29  	buf = buf[:0]
    30  	argPos := 0
    31  
    32  	data := []byte(query)
    33  
    34  	for i := range data {
    35  		q := query[i]
    36  		switch q {
    37  		case '?':
    38  			arg := args[argPos]
    39  			argPos++
    40  
    41  			if arg == nil {
    42  				buf = append(buf, "NULL"...)
    43  				continue
    44  			}
    45  
    46  			switch v := arg.(type) {
    47  			case int64:
    48  				buf = strconv.AppendInt(buf, v, 10)
    49  			case float64:
    50  				buf = strconv.AppendFloat(buf, v, 'g', -1, 64)
    51  			case bool:
    52  				if v {
    53  					buf = append(buf, '1')
    54  				} else {
    55  					buf = append(buf, '0')
    56  				}
    57  			case time.Time:
    58  				if v.IsZero() {
    59  					buf = append(buf, "'0000-00-00'"...)
    60  				} else {
    61  					v := v.In(loc)
    62  					v = v.Add(time.Nanosecond * 500) // Write round under microsecond
    63  					year := v.Year()
    64  					year100 := year / 100
    65  					year1 := year % 100
    66  					month := v.Month()
    67  					day := v.Day()
    68  					hour := v.Hour()
    69  					minute := v.Minute()
    70  					second := v.Second()
    71  					micro := v.Nanosecond() / 1000
    72  
    73  					buf = append(buf, []byte{
    74  						'\'',
    75  						digits10[year100], digits01[year100],
    76  						digits10[year1], digits01[year1],
    77  						'-',
    78  						digits10[month], digits01[month],
    79  						'-',
    80  						digits10[day], digits01[day],
    81  						' ',
    82  						digits10[hour], digits01[hour],
    83  						':',
    84  						digits10[minute], digits01[minute],
    85  						':',
    86  						digits10[second], digits01[second],
    87  					}...)
    88  
    89  					if micro != 0 {
    90  						micro10000 := micro / 10000
    91  						micro100 := micro / 100 % 100
    92  						micro1 := micro % 100
    93  						buf = append(buf, []byte{
    94  							'.',
    95  							digits10[micro10000], digits01[micro10000],
    96  							digits10[micro100], digits01[micro100],
    97  							digits10[micro1], digits01[micro1],
    98  						}...)
    99  					}
   100  					buf = append(buf, '\'')
   101  				}
   102  			case []byte:
   103  				if v == nil {
   104  					buf = append(buf, "NULL"...)
   105  				} else {
   106  					buf = append(buf, "_binary'"...)
   107  					buf = escapeBytesBackslash(buf, v)
   108  					buf = append(buf, '\'')
   109  				}
   110  			case string:
   111  				buf = append(buf, '\'')
   112  				buf = escapeBytesBackslash(buf, []byte(v))
   113  				buf = append(buf, '\'')
   114  			default:
   115  				return "", driver.ErrSkip
   116  			}
   117  
   118  		case '\n':
   119  			buf = append(buf, ' ')
   120  		default:
   121  			buf = append(buf, q)
   122  		}
   123  
   124  		if len(buf)+4 > maxAllowedPacket {
   125  			return "", driver.ErrSkip
   126  		}
   127  	}
   128  	if argPos != len(args) {
   129  		return "", driver.ErrSkip
   130  	}
   131  	return string(buf), nil
   132  }
   133  
   134  // copy from mysql driver
   135  
   136  const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
   137  const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
   138  
   139  func escapeBytesBackslash(buf, v []byte) []byte {
   140  	pos := len(buf)
   141  	buf = reserveBuffer(buf, len(v)*2)
   142  
   143  	for _, c := range v {
   144  		switch c {
   145  		case '\x00':
   146  			buf[pos] = '\\'
   147  			buf[pos+1] = '0'
   148  			pos += 2
   149  		case '\n':
   150  			buf[pos] = '\\'
   151  			buf[pos+1] = 'n'
   152  			pos += 2
   153  		case '\r':
   154  			buf[pos] = '\\'
   155  			buf[pos+1] = 'r'
   156  			pos += 2
   157  		case '\x1a':
   158  			buf[pos] = '\\'
   159  			buf[pos+1] = 'Z'
   160  			pos += 2
   161  		case '\'':
   162  			buf[pos] = '\\'
   163  			buf[pos+1] = '\''
   164  			pos += 2
   165  		case '"':
   166  			buf[pos] = '\\'
   167  			buf[pos+1] = '"'
   168  			pos += 2
   169  		case '\\':
   170  			buf[pos] = '\\'
   171  			buf[pos+1] = '\\'
   172  			pos += 2
   173  		default:
   174  			buf[pos] = c
   175  			pos++
   176  		}
   177  	}
   178  
   179  	return buf[:pos]
   180  }
   181  
   182  func reserveBuffer(buf []byte, appendSize int) []byte {
   183  	newSize := len(buf) + appendSize
   184  	if cap(buf) < newSize {
   185  		// Grow buffer exponentially
   186  		newBuf := make([]byte, len(buf)*2+appendSize)
   187  		copy(newBuf, buf)
   188  		buf = newBuf
   189  	}
   190  	return buf[:newSize]
   191  }