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 }