| 246 | } |
| 247 | |
| 248 | func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { |
| 249 | noBackslashEscapes := (mc.status & statusNoBackslashEscapes) != 0 |
| 250 | const ( |
| 251 | stateNormal = iota |
| 252 | stateString |
| 253 | stateEscape |
| 254 | stateEOLComment |
| 255 | stateSlashStarComment |
| 256 | stateBacktick |
| 257 | ) |
| 258 | |
| 259 | const ( |
| 260 | QUOTE_BYTE = byte('\'') |
| 261 | DBL_QUOTE_BYTE = byte('"') |
| 262 | BACKSLASH_BYTE = byte('\\') |
| 263 | QUESTION_MARK_BYTE = byte('?') |
| 264 | SLASH_BYTE = byte('/') |
| 265 | STAR_BYTE = byte('*') |
| 266 | HASH_BYTE = byte('#') |
| 267 | MINUS_BYTE = byte('-') |
| 268 | LINE_FEED_BYTE = byte('\n') |
| 269 | BACKTICK_BYTE = byte('`') |
| 270 | ) |
| 271 | |
| 272 | buf, err := mc.buf.takeCompleteBuffer() |
| 273 | if err != nil { |
| 274 | mc.cleanup() |
| 275 | return "", driver.ErrBadConn |
| 276 | } |
| 277 | buf = buf[:0] |
| 278 | state := stateNormal |
| 279 | singleQuotes := false |
| 280 | lastChar := byte(0) |
| 281 | argPos := 0 |
| 282 | lenQuery := len(query) |
| 283 | lastIdx := 0 |
| 284 | |
| 285 | for i := range lenQuery { |
| 286 | currentChar := query[i] |
| 287 | if state == stateEscape && !((currentChar == QUOTE_BYTE && singleQuotes) || (currentChar == DBL_QUOTE_BYTE && !singleQuotes)) { |
| 288 | state = stateString |
| 289 | lastChar = currentChar |
| 290 | continue |
| 291 | } |
| 292 | switch currentChar { |
| 293 | case STAR_BYTE: |
| 294 | if state == stateNormal && lastChar == SLASH_BYTE { |
| 295 | state = stateSlashStarComment |
| 296 | } |
| 297 | case SLASH_BYTE: |
| 298 | if state == stateSlashStarComment && lastChar == STAR_BYTE { |
| 299 | state = stateNormal |
| 300 | // Clear lastChar so the '/' that closed the comment isn't |
| 301 | // reused to start a new comment with a following '*'. |
| 302 | lastChar = 0 |
| 303 | continue |
| 304 | } |
| 305 | case HASH_BYTE: |