100 lines
1.9 KiB
Go
100 lines
1.9 KiB
Go
package mysql
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
// splitSQL supports ordinary migration statements, quoted values and comments.
|
|
// Stored routines and DELIMITER scripts are intentionally unsupported.
|
|
func splitSQL(src string) ([]string, error) {
|
|
var out []string
|
|
var b strings.Builder
|
|
var quote byte
|
|
lineComment, blockComment := false, false
|
|
flush := func() error {
|
|
s := strings.TrimSpace(b.String())
|
|
b.Reset()
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
if strings.HasPrefix(strings.ToUpper(s), "DELIMITER") {
|
|
return errors.New("DELIMITER scripts are unsupported")
|
|
}
|
|
out = append(out, s)
|
|
return nil
|
|
}
|
|
for i := 0; i < len(src); i++ {
|
|
c := src[i]
|
|
if lineComment {
|
|
if c == '\n' {
|
|
lineComment = false
|
|
b.WriteByte(' ')
|
|
}
|
|
continue
|
|
}
|
|
if blockComment {
|
|
if c == '*' && i+1 < len(src) && src[i+1] == '/' {
|
|
blockComment = false
|
|
i++
|
|
b.WriteByte(' ')
|
|
}
|
|
continue
|
|
}
|
|
if quote != 0 {
|
|
b.WriteByte(c)
|
|
if c == '\\' && i+1 < len(src) {
|
|
i++
|
|
b.WriteByte(src[i])
|
|
continue
|
|
}
|
|
if c == quote {
|
|
if i+1 < len(src) && src[i+1] == quote {
|
|
i++
|
|
b.WriteByte(src[i])
|
|
} else {
|
|
quote = 0
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if c == '#' || c == '-' && i+2 < len(src) && src[i+1] == '-' && src[i+2] <= ' ' {
|
|
lineComment = true
|
|
if c == '-' {
|
|
i++
|
|
}
|
|
continue
|
|
}
|
|
if c == '/' && i+1 < len(src) && src[i+1] == '*' {
|
|
if i+2 < len(src) && src[i+2] == '!' {
|
|
return nil, errors.New("executable SQL comments are unsupported")
|
|
}
|
|
blockComment = true
|
|
i++
|
|
continue
|
|
}
|
|
if c == '\'' || c == '"' || c == '`' {
|
|
quote = c
|
|
b.WriteByte(c)
|
|
continue
|
|
}
|
|
if c == ';' {
|
|
if err := flush(); err != nil {
|
|
return nil, err
|
|
}
|
|
continue
|
|
}
|
|
b.WriteByte(c)
|
|
}
|
|
if quote != 0 || blockComment {
|
|
return nil, errors.New("unterminated SQL quote or comment")
|
|
}
|
|
if err := flush(); err != nil {
|
|
return nil, err
|
|
}
|
|
if len(out) == 0 {
|
|
return nil, errors.New("empty migration")
|
|
}
|
|
return out, nil
|
|
}
|