(source, keyword string, start, end int, last bool)
| 398 | } |
| 399 | |
| 400 | func findKeywordOutsideSQL(source, keyword string, start, end int, last bool) int { |
| 401 | if start >= end { |
| 402 | return -1 |
| 403 | } |
| 404 | result := -1 |
| 405 | for i := start; i < end; { |
| 406 | switch source[i] { |
| 407 | case '\'': |
| 408 | i = skipQuotedSQL(source, i, end, '\'') |
| 409 | case '"': |
| 410 | i = skipQuotedSQL(source, i, end, '"') |
| 411 | case '[': |
| 412 | i = skipQuotedSQL(source, i, end, ']') |
| 413 | case '-': |
| 414 | if i+1 < end && source[i+1] == '-' { |
| 415 | i = skipLineComment(source, i+2, end) |
| 416 | continue |
| 417 | } |
| 418 | if keywordMatchAt(source, keyword, i, start, end) { |
| 419 | if !last { |
| 420 | return i |
| 421 | } |
| 422 | result = i |
| 423 | i += len(keyword) |
| 424 | continue |
| 425 | } |
| 426 | i++ |
| 427 | case '/': |
| 428 | if i+1 < end && source[i+1] == '*' { |
| 429 | i = skipBlockComment(source, i+2, end) |
| 430 | continue |
| 431 | } |
| 432 | if keywordMatchAt(source, keyword, i, start, end) { |
| 433 | if !last { |
| 434 | return i |
| 435 | } |
| 436 | result = i |
| 437 | i += len(keyword) |
| 438 | continue |
| 439 | } |
| 440 | i++ |
| 441 | default: |
| 442 | if keywordMatchAt(source, keyword, i, start, end) { |
| 443 | if !last { |
| 444 | return i |
| 445 | } |
| 446 | result = i |
| 447 | i += len(keyword) |
| 448 | continue |
| 449 | } |
| 450 | i++ |
| 451 | } |
| 452 | } |
| 453 | return result |
| 454 | } |
| 455 | |
| 456 | func keywordMatchAt(source, keyword string, offset, start, end int) bool { |
| 457 | if offset+len(keyword) > end || !strings.EqualFold(source[offset:offset+len(keyword)], keyword) { |
no test coverage detected