ddlmod.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package sqlite
  2. import (
  3. "errors"
  4. "fmt"
  5. "regexp"
  6. "strings"
  7. )
  8. type ddl struct {
  9. head string
  10. fields []string
  11. }
  12. func parseDDL(sql string) (*ddl, error) {
  13. reg := regexp.MustCompile("(?i)(CREATE TABLE [\"`]?[\\w\\d]+[\"`]?)(?: \\((.*)\\))?")
  14. sections := reg.FindStringSubmatch(sql)
  15. if sections == nil {
  16. return nil, errors.New("invalid DDL")
  17. }
  18. ddlHead := sections[1]
  19. ddlBody := sections[2]
  20. ddlBodyRunes := []rune(ddlBody)
  21. fields := []string{}
  22. bracketLevel := 0
  23. var quote rune = 0
  24. buf := ""
  25. for i := 0; i < len(ddlBodyRunes); i++ {
  26. c := ddlBodyRunes[i]
  27. var next rune = 0
  28. if i+1 < len(ddlBodyRunes) {
  29. next = ddlBodyRunes[i+1]
  30. }
  31. if c == '\'' || c == '"' || c == '`' {
  32. if c == next {
  33. // Skip escaped quote
  34. buf += string(c)
  35. i++
  36. } else if quote > 0 {
  37. quote = 0
  38. } else {
  39. quote = c
  40. }
  41. } else if quote == 0 {
  42. if c == '(' {
  43. bracketLevel++
  44. } else if c == ')' {
  45. bracketLevel--
  46. } else if bracketLevel == 0 {
  47. if c == ',' {
  48. fields = append(fields, strings.TrimSpace(buf))
  49. buf = ""
  50. continue
  51. }
  52. }
  53. }
  54. if bracketLevel < 0 {
  55. return nil, errors.New("invalid DDL, unbalanced brackets")
  56. }
  57. buf += string(c)
  58. }
  59. if bracketLevel != 0 {
  60. return nil, errors.New("invalid DDL, unbalanced brackets")
  61. }
  62. if buf != "" {
  63. fields = append(fields, strings.TrimSpace(buf))
  64. }
  65. return &ddl{head: ddlHead, fields: fields}, nil
  66. }
  67. func (d *ddl) compile() string {
  68. if len(d.fields) == 0 {
  69. return d.head
  70. }
  71. return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ","))
  72. }
  73. func (d *ddl) addConstraint(name string, sql string) {
  74. reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
  75. for i := 0; i < len(d.fields); i++ {
  76. if reg.MatchString(d.fields[i]) {
  77. d.fields[i] = sql
  78. return
  79. }
  80. }
  81. d.fields = append(d.fields, sql)
  82. }
  83. func (d *ddl) removeConstraint(name string) bool {
  84. reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
  85. for i := 0; i < len(d.fields); i++ {
  86. if reg.MatchString(d.fields[i]) {
  87. d.fields = append(d.fields[:i], d.fields[i+1:]...)
  88. return true
  89. }
  90. }
  91. return false
  92. }
  93. func (d *ddl) hasConstraint(name string) bool {
  94. reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
  95. for _, f := range d.fields {
  96. if reg.MatchString(f) {
  97. return true
  98. }
  99. }
  100. return false
  101. }
  102. func (d *ddl) getColumns() []string {
  103. res := []string{}
  104. for _, f := range d.fields {
  105. fUpper := strings.ToUpper(f)
  106. if strings.HasPrefix(fUpper, "PRIMARY KEY") ||
  107. strings.HasPrefix(fUpper, "CHECK") ||
  108. strings.HasPrefix(fUpper, "CONSTRAINT") {
  109. continue
  110. }
  111. reg := regexp.MustCompile("^[\"`]?([\\w\\d]+)[\"`]?")
  112. match := reg.FindStringSubmatch(f)
  113. if match != nil {
  114. res = append(res, "`"+match[1]+"`")
  115. }
  116. }
  117. return res
  118. }