You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
7.5 KiB

  1. // Copyright 2015 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package tidb
  5. import (
  6. "errors"
  7. "fmt"
  8. "strconv"
  9. "strings"
  10. "github.com/go-xorm/core"
  11. )
  12. type tidb struct {
  13. core.Base
  14. }
  15. func (db *tidb) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
  16. return db.Base.Init(d, db, uri, drivername, dataSourceName)
  17. }
  18. func (db *tidb) SqlType(c *core.Column) string {
  19. var res string
  20. switch t := c.SQLType.Name; t {
  21. case core.Bool:
  22. res = core.Bool
  23. case core.Serial:
  24. c.IsAutoIncrement = true
  25. c.IsPrimaryKey = true
  26. c.Nullable = false
  27. res = core.Int
  28. case core.BigSerial:
  29. c.IsAutoIncrement = true
  30. c.IsPrimaryKey = true
  31. c.Nullable = false
  32. res = core.BigInt
  33. case core.Bytea:
  34. res = core.Blob
  35. case core.TimeStampz:
  36. res = core.Char
  37. c.Length = 64
  38. case core.Enum: //mysql enum
  39. res = core.Enum
  40. res += "("
  41. opts := ""
  42. for v, _ := range c.EnumOptions {
  43. opts += fmt.Sprintf(",'%v'", v)
  44. }
  45. res += strings.TrimLeft(opts, ",")
  46. res += ")"
  47. case core.Set: //mysql set
  48. res = core.Set
  49. res += "("
  50. opts := ""
  51. for v, _ := range c.SetOptions {
  52. opts += fmt.Sprintf(",'%v'", v)
  53. }
  54. res += strings.TrimLeft(opts, ",")
  55. res += ")"
  56. case core.NVarchar:
  57. res = core.Varchar
  58. case core.Uuid:
  59. res = core.Varchar
  60. c.Length = 40
  61. case core.Json:
  62. res = core.Text
  63. default:
  64. res = t
  65. }
  66. var hasLen1 bool = (c.Length > 0)
  67. var hasLen2 bool = (c.Length2 > 0)
  68. if res == core.BigInt && !hasLen1 && !hasLen2 {
  69. c.Length = 20
  70. hasLen1 = true
  71. }
  72. if hasLen2 {
  73. res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
  74. } else if hasLen1 {
  75. res += "(" + strconv.Itoa(c.Length) + ")"
  76. }
  77. return res
  78. }
  79. func (db *tidb) SupportInsertMany() bool {
  80. return true
  81. }
  82. func (db *tidb) IsReserved(name string) bool {
  83. return false
  84. }
  85. func (db *tidb) Quote(name string) string {
  86. return "`" + name + "`"
  87. }
  88. func (db *tidb) QuoteStr() string {
  89. return "`"
  90. }
  91. func (db *tidb) SupportEngine() bool {
  92. return false
  93. }
  94. func (db *tidb) AutoIncrStr() string {
  95. return "AUTO_INCREMENT"
  96. }
  97. func (db *tidb) SupportCharset() bool {
  98. return false
  99. }
  100. func (db *tidb) IndexOnTable() bool {
  101. return true
  102. }
  103. func (db *tidb) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
  104. args := []interface{}{db.DbName, tableName, idxName}
  105. sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
  106. sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
  107. return sql, args
  108. }
  109. func (db *tidb) TableCheckSql(tableName string) (string, []interface{}) {
  110. args := []interface{}{db.DbName, tableName}
  111. sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
  112. return sql, args
  113. }
  114. func (db *tidb) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
  115. args := []interface{}{db.DbName, tableName}
  116. s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
  117. " `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
  118. rows, err := db.DB().Query(s, args...)
  119. db.LogSQL(s, args)
  120. if err != nil {
  121. return nil, nil, err
  122. }
  123. defer rows.Close()
  124. cols := make(map[string]*core.Column)
  125. colSeq := make([]string, 0)
  126. for rows.Next() {
  127. col := new(core.Column)
  128. col.Indexes = make(map[string]int)
  129. var columnName, isNullable, colType, colKey, extra string
  130. var colDefault *string
  131. err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra)
  132. if err != nil {
  133. return nil, nil, err
  134. }
  135. col.Name = strings.Trim(columnName, "` ")
  136. if "YES" == isNullable {
  137. col.Nullable = true
  138. }
  139. if colDefault != nil {
  140. col.Default = *colDefault
  141. if col.Default == "" {
  142. col.DefaultIsEmpty = true
  143. }
  144. }
  145. cts := strings.Split(colType, "(")
  146. colName := cts[0]
  147. colType = strings.ToUpper(colName)
  148. var len1, len2 int
  149. if len(cts) == 2 {
  150. idx := strings.Index(cts[1], ")")
  151. if colType == core.Enum && cts[1][0] == '\'' { //enum
  152. options := strings.Split(cts[1][0:idx], ",")
  153. col.EnumOptions = make(map[string]int)
  154. for k, v := range options {
  155. v = strings.TrimSpace(v)
  156. v = strings.Trim(v, "'")
  157. col.EnumOptions[v] = k
  158. }
  159. } else if colType == core.Set && cts[1][0] == '\'' {
  160. options := strings.Split(cts[1][0:idx], ",")
  161. col.SetOptions = make(map[string]int)
  162. for k, v := range options {
  163. v = strings.TrimSpace(v)
  164. v = strings.Trim(v, "'")
  165. col.SetOptions[v] = k
  166. }
  167. } else {
  168. lens := strings.Split(cts[1][0:idx], ",")
  169. len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
  170. if err != nil {
  171. return nil, nil, err
  172. }
  173. if len(lens) == 2 {
  174. len2, err = strconv.Atoi(lens[1])
  175. if err != nil {
  176. return nil, nil, err
  177. }
  178. }
  179. }
  180. }
  181. if colType == "FLOAT UNSIGNED" {
  182. colType = "FLOAT"
  183. }
  184. col.Length = len1
  185. col.Length2 = len2
  186. if _, ok := core.SqlTypes[colType]; ok {
  187. col.SQLType = core.SQLType{colType, len1, len2}
  188. } else {
  189. return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
  190. }
  191. if colKey == "PRI" {
  192. col.IsPrimaryKey = true
  193. }
  194. if colKey == "UNI" {
  195. //col.is
  196. }
  197. if extra == "auto_increment" {
  198. col.IsAutoIncrement = true
  199. }
  200. if col.SQLType.IsText() || col.SQLType.IsTime() {
  201. if col.Default != "" {
  202. col.Default = "'" + col.Default + "'"
  203. } else {
  204. if col.DefaultIsEmpty {
  205. col.Default = "''"
  206. }
  207. }
  208. }
  209. cols[col.Name] = col
  210. colSeq = append(colSeq, col.Name)
  211. }
  212. return colSeq, cols, nil
  213. }
  214. func (db *tidb) GetTables() ([]*core.Table, error) {
  215. args := []interface{}{db.DbName}
  216. s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
  217. "`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')"
  218. rows, err := db.DB().Query(s, args...)
  219. db.LogSQL(s, args)
  220. if err != nil {
  221. return nil, err
  222. }
  223. defer rows.Close()
  224. tables := make([]*core.Table, 0)
  225. for rows.Next() {
  226. table := core.NewEmptyTable()
  227. var name, engine, tableRows string
  228. var autoIncr *string
  229. err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
  230. if err != nil {
  231. return nil, err
  232. }
  233. table.Name = name
  234. table.StoreEngine = engine
  235. tables = append(tables, table)
  236. }
  237. return tables, nil
  238. }
  239. func (db *tidb) GetIndexes(tableName string) (map[string]*core.Index, error) {
  240. args := []interface{}{db.DbName, tableName}
  241. s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
  242. rows, err := db.DB().Query(s, args...)
  243. db.LogSQL(s, args)
  244. if err != nil {
  245. return nil, err
  246. }
  247. defer rows.Close()
  248. indexes := make(map[string]*core.Index, 0)
  249. for rows.Next() {
  250. var indexType int
  251. var indexName, colName, nonUnique string
  252. err = rows.Scan(&indexName, &nonUnique, &colName)
  253. if err != nil {
  254. return nil, err
  255. }
  256. if indexName == "PRIMARY" {
  257. continue
  258. }
  259. if "YES" == nonUnique || nonUnique == "1" {
  260. indexType = core.IndexType
  261. } else {
  262. indexType = core.UniqueType
  263. }
  264. colName = strings.Trim(colName, "` ")
  265. var isRegular bool
  266. if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
  267. indexName = indexName[5+len(tableName) : len(indexName)]
  268. isRegular = true
  269. }
  270. var index *core.Index
  271. var ok bool
  272. if index, ok = indexes[indexName]; !ok {
  273. index = new(core.Index)
  274. index.IsRegular = isRegular
  275. index.Type = indexType
  276. index.Name = indexName
  277. indexes[indexName] = index
  278. }
  279. index.AddColumn(colName)
  280. }
  281. return indexes, nil
  282. }
  283. func (db *tidb) Filters() []core.Filter {
  284. return []core.Filter{&core.IdFilter{}}
  285. }