You've already forked golang-base-project
145 lines
2.8 KiB
Go
145 lines
2.8 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
type ddl struct {
|
|
head string
|
|
fields []string
|
|
}
|
|
|
|
func parseDDL(sql string) (*ddl, error) {
|
|
reg := regexp.MustCompile("(?i)(CREATE TABLE [\"`]?[\\w\\d]+[\"`]?)(?: \\((.*)\\))?")
|
|
sections := reg.FindStringSubmatch(sql)
|
|
|
|
if sections == nil {
|
|
return nil, errors.New("invalid DDL")
|
|
}
|
|
|
|
ddlHead := sections[1]
|
|
ddlBody := sections[2]
|
|
ddlBodyRunes := []rune(ddlBody)
|
|
fields := []string{}
|
|
|
|
bracketLevel := 0
|
|
var quote rune = 0
|
|
buf := ""
|
|
|
|
for i := 0; i < len(ddlBodyRunes); i++ {
|
|
c := ddlBodyRunes[i]
|
|
var next rune = 0
|
|
if i+1 < len(ddlBodyRunes) {
|
|
next = ddlBodyRunes[i+1]
|
|
}
|
|
|
|
if c == '\'' || c == '"' || c == '`' {
|
|
if c == next {
|
|
// Skip escaped quote
|
|
buf += string(c)
|
|
i++
|
|
} else if quote > 0 {
|
|
quote = 0
|
|
} else {
|
|
quote = c
|
|
}
|
|
} else if quote == 0 {
|
|
if c == '(' {
|
|
bracketLevel++
|
|
} else if c == ')' {
|
|
bracketLevel--
|
|
} else if bracketLevel == 0 {
|
|
if c == ',' {
|
|
fields = append(fields, strings.TrimSpace(buf))
|
|
buf = ""
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
if bracketLevel < 0 {
|
|
return nil, errors.New("invalid DDL, unbalanced brackets")
|
|
}
|
|
|
|
buf += string(c)
|
|
}
|
|
|
|
if bracketLevel != 0 {
|
|
return nil, errors.New("invalid DDL, unbalanced brackets")
|
|
}
|
|
|
|
if buf != "" {
|
|
fields = append(fields, strings.TrimSpace(buf))
|
|
}
|
|
|
|
return &ddl{head: ddlHead, fields: fields}, nil
|
|
}
|
|
|
|
func (d *ddl) compile() string {
|
|
if len(d.fields) == 0 {
|
|
return d.head
|
|
}
|
|
|
|
return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ","))
|
|
}
|
|
|
|
func (d *ddl) addConstraint(name string, sql string) {
|
|
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
|
|
|
|
for i := 0; i < len(d.fields); i++ {
|
|
if reg.MatchString(d.fields[i]) {
|
|
d.fields[i] = sql
|
|
return
|
|
}
|
|
}
|
|
|
|
d.fields = append(d.fields, sql)
|
|
}
|
|
|
|
func (d *ddl) removeConstraint(name string) bool {
|
|
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
|
|
|
|
for i := 0; i < len(d.fields); i++ {
|
|
if reg.MatchString(d.fields[i]) {
|
|
d.fields = append(d.fields[:i], d.fields[i+1:]...)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (d *ddl) hasConstraint(name string) bool {
|
|
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
|
|
|
|
for _, f := range d.fields {
|
|
if reg.MatchString(f) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (d *ddl) getColumns() []string {
|
|
res := []string{}
|
|
|
|
for _, f := range d.fields {
|
|
fUpper := strings.ToUpper(f)
|
|
if strings.HasPrefix(fUpper, "PRIMARY KEY") ||
|
|
strings.HasPrefix(fUpper, "CHECK") ||
|
|
strings.HasPrefix(fUpper, "CONSTRAINT") {
|
|
continue
|
|
}
|
|
|
|
reg := regexp.MustCompile("^[\"`]?([\\w\\d]+)[\"`]?")
|
|
match := reg.FindStringSubmatch(f)
|
|
|
|
if match != nil {
|
|
res = append(res, "`"+match[1]+"`")
|
|
}
|
|
}
|
|
return res
|
|
}
|