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 }