package db import "strings" // SplitStatements 按分号切分 SQL 为多条语句,忽略单/双引号字符串与 // 行注释(--、#)、块注释(/* */)内的分号。语义对齐前端 sql.ts splitStatements。 // 返回的语句已去除首尾空白,空语句被丢弃。 func SplitStatements(sql string) []string { var out []string var cur strings.Builder i := 0 n := len(sql) inS, inD, inLine, inBlock := false, false, false, false flush := func() { if s := strings.TrimSpace(cur.String()); s != "" { out = append(out, s) } cur.Reset() } for i < n { ch := sql[i] var nxt byte if i+1 < n { nxt = sql[i+1] } switch { case inLine: cur.WriteByte(ch) if ch == '\n' { inLine = false } i++ case inBlock: cur.WriteByte(ch) if ch == '*' && nxt == '/' { cur.WriteByte(nxt) inBlock = false i += 2 } else { i++ } case !inS && !inD && ch == '-' && nxt == '-': inLine = true cur.WriteString("--") i += 2 case !inS && !inD && ch == '#': inLine = true cur.WriteByte(ch) i++ case !inS && !inD && ch == '/' && nxt == '*': inBlock = true cur.WriteString("/*") i += 2 case ch == '\'' && !inD: inS = !inS cur.WriteByte(ch) i++ case ch == '"' && !inS: inD = !inD cur.WriteByte(ch) i++ case ch == ';' && !inS && !inD: flush() i++ default: cur.WriteByte(ch) i++ } } flush() return out } // StripComments 剥除 --、#、/* */ 注释,并把字符串字面量替换为 ” 占位, // 便于在纯代码文本上做危险关键字判定。 // MySQL 可执行注释 /*! ... */ 的内容会被保留参与检查(去掉包裹的 /*! 与 */)。 func StripComments(sql string) string { var b strings.Builder b.Grow(len(sql)) i := 0 n := len(sql) for i < n { ch := sql[i] var nxt byte if i+1 < n { nxt = sql[i+1] } switch { // 行注释 -- 与 # case ch == '-' && nxt == '-': for i < n && sql[i] != '\n' { i++ } b.WriteByte(' ') case ch == '#': for i < n && sql[i] != '\n' { i++ } b.WriteByte(' ') // 块注释;/*! ... */ 为 MySQL 可执行注释,保留内容 case ch == '/' && nxt == '*': exec := i+2 < n && sql[i+2] == '!' start := i + 2 if exec { start = i + 3 } j := strings.Index(sql[start:], "*/") if j < 0 { if exec { b.WriteString(sql[start:]) } return b.String() } if exec { b.WriteByte(' ') b.WriteString(sql[start : start+j]) b.WriteByte(' ') } else { b.WriteByte(' ') } i = start + j + 2 // 单引号字面量(处理 '' 与 \' 转义) case ch == '\'': b.WriteString("''") i++ for i < n { if sql[i] == '\'' { if i+1 < n && sql[i+1] == '\'' { i += 2 continue } i++ break } if sql[i] == '\\' && i+1 < n { i += 2 continue } i++ } // 双引号标识符/字面量同样置空内容(防 "DROP" 作为标识符误报) case ch == '"': b.WriteString(`""`) i++ for i < n { if sql[i] == '"' { if i+1 < n && sql[i+1] == '"' { i += 2 continue } i++ break } i++ } // 反引号标识符内容置空 case ch == '`': b.WriteString("``") i++ for i < n && sql[i] != '`' { i++ } if i < n { i++ } default: b.WriteByte(ch) i++ } } return b.String() }