Archived
Template
1
0
This repository has been archived on 2023-12-20. You can view files and clone it, but cannot push or open issues or pull requests.
Files
2021-12-12 14:56:13 +01:00

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
}