columninfo.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package mysql
  15. import (
  16. "fmt"
  17. "math/bits"
  18. "regexp"
  19. "strconv"
  20. "strings"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/utils"
  23. "yunion.io/x/sqlchemy"
  24. )
  25. type sSqlColumnInfo struct {
  26. Field string
  27. Type string
  28. Collation string
  29. Null string
  30. Key string
  31. Default string
  32. Extra string
  33. Privileges string
  34. Comment string
  35. }
  36. func decodeSqlTypeString(typeStr string) []string {
  37. typeReg := regexp.MustCompile(`(\w+)\((\d+)(,\s*(\d+))?\)`)
  38. matches := typeReg.FindStringSubmatch(typeStr)
  39. if len(matches) >= 3 {
  40. return matches[1:]
  41. }
  42. parts := strings.Split(typeStr, " ")
  43. return []string{parts[0]}
  44. }
  45. func (info *sSqlColumnInfo) toColumnSpec() sqlchemy.IColumnSpec {
  46. tagmap := make(map[string]string)
  47. matches := decodeSqlTypeString(info.Type)
  48. typeStr := strings.ToUpper(matches[0])
  49. width := 0
  50. if len(matches) > 1 {
  51. width, _ = strconv.Atoi(matches[1])
  52. }
  53. if width > 0 {
  54. tagmap[sqlchemy.TAG_WIDTH] = fmt.Sprintf("%d", width)
  55. }
  56. if info.Null == "YES" {
  57. tagmap[sqlchemy.TAG_NULLABLE] = "true"
  58. } else {
  59. tagmap[sqlchemy.TAG_NULLABLE] = "false"
  60. }
  61. if info.Key == "PRI" {
  62. tagmap[sqlchemy.TAG_PRIMARY] = "true"
  63. } else {
  64. tagmap[sqlchemy.TAG_PRIMARY] = "false"
  65. }
  66. charset := ""
  67. if info.Collation == "ascii_general_ci" {
  68. charset = "ascii"
  69. } else if info.Collation == "utf8_general_ci" || info.Collation == "utf8mb4_unicode_ci" {
  70. charset = "utf8"
  71. } else {
  72. charset = "ascii"
  73. }
  74. if len(charset) > 0 {
  75. tagmap[sqlchemy.TAG_CHARSET] = charset
  76. }
  77. if info.Default != "NULL" {
  78. tagmap[sqlchemy.TAG_DEFAULT] = info.Default
  79. }
  80. if strings.HasSuffix(typeStr, "CHAR") {
  81. c := NewTextColumn(info.Field, typeStr, tagmap, false)
  82. return &c
  83. } else if strings.HasSuffix(typeStr, "TEXT") {
  84. tagmap[sqlchemy.TAG_TEXT_LENGTH] = typeStr[:len(typeStr)-4]
  85. c := NewTextColumn(info.Field, typeStr, tagmap, false)
  86. return &c
  87. } else if strings.HasSuffix(typeStr, "INT") {
  88. if info.Extra == "auto_increment" {
  89. tagmap[sqlchemy.TAG_AUTOINCREMENT] = "true"
  90. }
  91. unsigned := false
  92. if strings.HasSuffix(info.Type, " unsigned") {
  93. unsigned = true
  94. }
  95. if _, ok := tagmap[sqlchemy.TAG_WIDTH]; !ok {
  96. if unsigned {
  97. tagmap[sqlchemy.TAG_WIDTH] = uintWidthString(typeStr)
  98. } else {
  99. tagmap[sqlchemy.TAG_WIDTH] = intWidthString(typeStr)
  100. }
  101. }
  102. c := NewIntegerColumn(info.Field, typeStr, unsigned, tagmap, false)
  103. return &c
  104. } else if typeStr == "FLOAT" || typeStr == "DOUBLE" {
  105. c := NewFloatColumn(info.Field, typeStr, tagmap, false)
  106. return &c
  107. } else if typeStr == "DECIMAL" {
  108. if len(matches) > 3 {
  109. precision, _ := strconv.Atoi(matches[3])
  110. if precision > 0 {
  111. tagmap[sqlchemy.TAG_PRECISION] = fmt.Sprintf("%d", precision)
  112. }
  113. }
  114. c := NewDecimalColumn(info.Field, tagmap, false)
  115. return &c
  116. } else if typeStr == "DATETIME" {
  117. c := NewDateTimeColumn(info.Field, tagmap, false)
  118. return &c
  119. } else if typeStr == "DATE" || typeStr == "TIMESTAMP" {
  120. c := NewTimeTypeColumn(info.Field, typeStr, tagmap, false)
  121. return &c
  122. } else if strings.HasPrefix(typeStr, "ENUM(") {
  123. // enum type, force convert to text
  124. // discourage use of enum, use text instead
  125. enums := utils.FindWords([]byte(typeStr[5:len(typeStr)-1]), 0)
  126. width := 0
  127. for i := range enums {
  128. if width < len(enums[i]) {
  129. width = len(enums[i])
  130. }
  131. }
  132. tagmap[sqlchemy.TAG_WIDTH] = fmt.Sprintf("%d", 1<<uint(bits.Len(uint(width))))
  133. c := NewTextColumn(info.Field, "VARCHAR", tagmap, false)
  134. return &c
  135. } else {
  136. log.Errorf("unsupported type %s", typeStr)
  137. return nil
  138. }
  139. }