mysql_dialect.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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 xorm
  5. import (
  6. "crypto/tls"
  7. "errors"
  8. "fmt"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "github.com/xormplus/core"
  13. )
  14. // func init() {
  15. // RegisterDialect("mysql", &mysql{})
  16. // }
  17. var (
  18. mysqlReservedWords = map[string]bool{
  19. "ADD": true,
  20. "ALL": true,
  21. "ALTER": true,
  22. "ANALYZE": true,
  23. "AND": true,
  24. "AS": true,
  25. "ASC": true,
  26. "ASENSITIVE": true,
  27. "BEFORE": true,
  28. "BETWEEN": true,
  29. "BIGINT": true,
  30. "BINARY": true,
  31. "BLOB": true,
  32. "BOTH": true,
  33. "BY": true,
  34. "CALL": true,
  35. "CASCADE": true,
  36. "CASE": true,
  37. "CHANGE": true,
  38. "CHAR": true,
  39. "CHARACTER": true,
  40. "CHECK": true,
  41. "COLLATE": true,
  42. "COLUMN": true,
  43. "CONDITION": true,
  44. "CONNECTION": true,
  45. "CONSTRAINT": true,
  46. "CONTINUE": true,
  47. "CONVERT": true,
  48. "CREATE": true,
  49. "CROSS": true,
  50. "CURRENT_DATE": true,
  51. "CURRENT_TIME": true,
  52. "CURRENT_TIMESTAMP": true,
  53. "CURRENT_USER": true,
  54. "CURSOR": true,
  55. "DATABASE": true,
  56. "DATABASES": true,
  57. "DAY_HOUR": true,
  58. "DAY_MICROSECOND": true,
  59. "DAY_MINUTE": true,
  60. "DAY_SECOND": true,
  61. "DEC": true,
  62. "DECIMAL": true,
  63. "DECLARE": true,
  64. "DEFAULT": true,
  65. "DELAYED": true,
  66. "DELETE": true,
  67. "DESC": true,
  68. "DESCRIBE": true,
  69. "DETERMINISTIC": true,
  70. "DISTINCT": true,
  71. "DISTINCTROW": true,
  72. "DIV": true,
  73. "DOUBLE": true,
  74. "DROP": true,
  75. "DUAL": true,
  76. "EACH": true,
  77. "ELSE": true,
  78. "ELSEIF": true,
  79. "ENCLOSED": true,
  80. "ESCAPED": true,
  81. "EXISTS": true,
  82. "EXIT": true,
  83. "EXPLAIN": true,
  84. "FALSE": true,
  85. "FETCH": true,
  86. "FLOAT": true,
  87. "FLOAT4": true,
  88. "FLOAT8": true,
  89. "FOR": true,
  90. "FORCE": true,
  91. "FOREIGN": true,
  92. "FROM": true,
  93. "FULLTEXT": true,
  94. "GOTO": true,
  95. "GRANT": true,
  96. "GROUP": true,
  97. "HAVING": true,
  98. "HIGH_PRIORITY": true,
  99. "HOUR_MICROSECOND": true,
  100. "HOUR_MINUTE": true,
  101. "HOUR_SECOND": true,
  102. "IF": true,
  103. "IGNORE": true,
  104. "IN": true, "INDEX": true,
  105. "INFILE": true, "INNER": true, "INOUT": true,
  106. "INSENSITIVE": true, "INSERT": true, "INT": true,
  107. "INT1": true, "INT2": true, "INT3": true,
  108. "INT4": true, "INT8": true, "INTEGER": true,
  109. "INTERVAL": true, "INTO": true, "IS": true,
  110. "ITERATE": true, "JOIN": true, "KEY": true,
  111. "KEYS": true, "KILL": true, "LABEL": true,
  112. "LEADING": true, "LEAVE": true, "LEFT": true,
  113. "LIKE": true, "LIMIT": true, "LINEAR": true,
  114. "LINES": true, "LOAD": true, "LOCALTIME": true,
  115. "LOCALTIMESTAMP": true, "LOCK": true, "LONG": true,
  116. "LONGBLOB": true, "LONGTEXT": true, "LOOP": true,
  117. "LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true,
  118. "MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true,
  119. "MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true,
  120. "MODIFIES": true, "NATURAL": true, "NOT": true,
  121. "NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true,
  122. "ON OPTIMIZE": true, "OPTION": true,
  123. "OPTIONALLY": true, "OR": true, "ORDER": true,
  124. "OUT": true, "OUTER": true, "OUTFILE": true,
  125. "PRECISION": true, "PRIMARY": true, "PROCEDURE": true,
  126. "PURGE": true, "RAID0": true, "RANGE": true,
  127. "READ": true, "READS": true, "REAL": true,
  128. "REFERENCES": true, "REGEXP": true, "RELEASE": true,
  129. "RENAME": true, "REPEAT": true, "REPLACE": true,
  130. "REQUIRE": true, "RESTRICT": true, "RETURN": true,
  131. "REVOKE": true, "RIGHT": true, "RLIKE": true,
  132. "SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true,
  133. "SELECT": true, "SENSITIVE": true, "SEPARATOR": true,
  134. "SET": true, "SHOW": true, "SMALLINT": true,
  135. "SPATIAL": true, "SPECIFIC": true, "SQL": true,
  136. "SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true,
  137. "SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true,
  138. "SSL": true, "STARTING": true, "STRAIGHT_JOIN": true,
  139. "TABLE": true, "TERMINATED": true, "THEN": true,
  140. "TINYBLOB": true, "TINYINT": true, "TINYTEXT": true,
  141. "TO": true, "TRAILING": true, "TRIGGER": true,
  142. "TRUE": true, "UNDO": true, "UNION": true,
  143. "UNIQUE": true, "UNLOCK": true, "UNSIGNED": true,
  144. "UPDATE": true, "USAGE": true, "USE": true,
  145. "USING": true, "UTC_DATE": true, "UTC_TIME": true,
  146. "UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true,
  147. "VARCHAR": true,
  148. "VARCHARACTER": true,
  149. "VARYING": true,
  150. "WHEN": true,
  151. "WHERE": true,
  152. "WHILE": true,
  153. "WITH": true,
  154. "WRITE": true,
  155. "X509": true,
  156. "XOR": true,
  157. "YEAR_MONTH": true,
  158. "ZEROFILL": true,
  159. }
  160. )
  161. type mysql struct {
  162. core.Base
  163. net string
  164. addr string
  165. params map[string]string
  166. loc *time.Location
  167. timeout time.Duration
  168. tls *tls.Config
  169. allowAllFiles bool
  170. allowOldPasswords bool
  171. clientFoundRows bool
  172. }
  173. func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
  174. return db.Base.Init(d, db, uri, drivername, dataSourceName)
  175. }
  176. func (db *mysql) SqlType(c *core.Column) string {
  177. var res string
  178. switch t := c.SQLType.Name; t {
  179. case core.Bool:
  180. res = core.TinyInt
  181. c.Length = 1
  182. case core.Serial:
  183. c.IsAutoIncrement = true
  184. c.IsPrimaryKey = true
  185. c.Nullable = false
  186. res = core.Int
  187. case core.BigSerial:
  188. c.IsAutoIncrement = true
  189. c.IsPrimaryKey = true
  190. c.Nullable = false
  191. res = core.BigInt
  192. case core.Bytea:
  193. res = core.Blob
  194. case core.TimeStampz:
  195. res = core.Char
  196. c.Length = 64
  197. case core.Enum: //mysql enum
  198. res = core.Enum
  199. res += "("
  200. opts := ""
  201. for v, _ := range c.EnumOptions {
  202. opts += fmt.Sprintf(",'%v'", v)
  203. }
  204. res += strings.TrimLeft(opts, ",")
  205. res += ")"
  206. case core.Set: //mysql set
  207. res = core.Set
  208. res += "("
  209. opts := ""
  210. for v, _ := range c.SetOptions {
  211. opts += fmt.Sprintf(",'%v'", v)
  212. }
  213. res += strings.TrimLeft(opts, ",")
  214. res += ")"
  215. case core.NVarchar:
  216. res = core.Varchar
  217. case core.Uuid:
  218. res = core.Varchar
  219. c.Length = 40
  220. case core.Json:
  221. res = core.Text
  222. default:
  223. res = t
  224. }
  225. var hasLen1 bool = (c.Length > 0)
  226. var hasLen2 bool = (c.Length2 > 0)
  227. if res == core.BigInt && !hasLen1 && !hasLen2 {
  228. c.Length = 20
  229. hasLen1 = true
  230. }
  231. if hasLen2 {
  232. res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
  233. } else if hasLen1 {
  234. res += "(" + strconv.Itoa(c.Length) + ")"
  235. }
  236. return res
  237. }
  238. func (db *mysql) SupportInsertMany() bool {
  239. return true
  240. }
  241. func (db *mysql) IsReserved(name string) bool {
  242. _, ok := mysqlReservedWords[name]
  243. return ok
  244. }
  245. func (db *mysql) Quote(name string) string {
  246. return "`" + name + "`"
  247. }
  248. func (db *mysql) QuoteStr() string {
  249. return "`"
  250. }
  251. func (db *mysql) SupportEngine() bool {
  252. return true
  253. }
  254. func (db *mysql) AutoIncrStr() string {
  255. return "AUTO_INCREMENT"
  256. }
  257. func (db *mysql) SupportCharset() bool {
  258. return true
  259. }
  260. func (db *mysql) IndexOnTable() bool {
  261. return true
  262. }
  263. func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
  264. args := []interface{}{db.DbName, tableName, idxName}
  265. sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
  266. sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
  267. return sql, args
  268. }
  269. /*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
  270. args := []interface{}{db.DbName, tableName, colName}
  271. sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
  272. return sql, args
  273. }*/
  274. func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
  275. args := []interface{}{db.DbName, tableName}
  276. sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
  277. return sql, args
  278. }
  279. func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
  280. args := []interface{}{db.DbName, tableName}
  281. s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
  282. " `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
  283. rows, err := db.DB().Query(s, args...)
  284. if db.Logger != nil {
  285. db.Logger.Info("[sql]", s, args)
  286. }
  287. if err != nil {
  288. return nil, nil, err
  289. }
  290. defer rows.Close()
  291. cols := make(map[string]*core.Column)
  292. colSeq := make([]string, 0)
  293. for rows.Next() {
  294. col := new(core.Column)
  295. col.Indexes = make(map[string]bool)
  296. var columnName, isNullable, colType, colKey, extra string
  297. var colDefault *string
  298. err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra)
  299. if err != nil {
  300. return nil, nil, err
  301. }
  302. col.Name = strings.Trim(columnName, "` ")
  303. if "YES" == isNullable {
  304. col.Nullable = true
  305. }
  306. if colDefault != nil {
  307. col.Default = *colDefault
  308. if col.Default == "" {
  309. col.DefaultIsEmpty = true
  310. }
  311. }
  312. cts := strings.Split(colType, "(")
  313. colName := cts[0]
  314. colType = strings.ToUpper(colName)
  315. var len1, len2 int
  316. if len(cts) == 2 {
  317. idx := strings.Index(cts[1], ")")
  318. if colType == core.Enum && cts[1][0] == '\'' { //enum
  319. options := strings.Split(cts[1][0:idx], ",")
  320. col.EnumOptions = make(map[string]int)
  321. for k, v := range options {
  322. v = strings.TrimSpace(v)
  323. v = strings.Trim(v, "'")
  324. col.EnumOptions[v] = k
  325. }
  326. } else if colType == core.Set && cts[1][0] == '\'' {
  327. options := strings.Split(cts[1][0:idx], ",")
  328. col.SetOptions = make(map[string]int)
  329. for k, v := range options {
  330. v = strings.TrimSpace(v)
  331. v = strings.Trim(v, "'")
  332. col.SetOptions[v] = k
  333. }
  334. } else {
  335. lens := strings.Split(cts[1][0:idx], ",")
  336. len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
  337. if err != nil {
  338. return nil, nil, err
  339. }
  340. if len(lens) == 2 {
  341. len2, err = strconv.Atoi(lens[1])
  342. if err != nil {
  343. return nil, nil, err
  344. }
  345. }
  346. }
  347. }
  348. if colType == "FLOAT UNSIGNED" {
  349. colType = "FLOAT"
  350. }
  351. col.Length = len1
  352. col.Length2 = len2
  353. if _, ok := core.SqlTypes[colType]; ok {
  354. col.SQLType = core.SQLType{colType, len1, len2}
  355. } else {
  356. return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
  357. }
  358. if colKey == "PRI" {
  359. col.IsPrimaryKey = true
  360. }
  361. if colKey == "UNI" {
  362. //col.is
  363. }
  364. if extra == "auto_increment" {
  365. col.IsAutoIncrement = true
  366. }
  367. if col.SQLType.IsText() || col.SQLType.IsTime() {
  368. if col.Default != "" {
  369. col.Default = "'" + col.Default + "'"
  370. } else {
  371. if col.DefaultIsEmpty {
  372. col.Default = "''"
  373. }
  374. }
  375. }
  376. cols[col.Name] = col
  377. colSeq = append(colSeq, col.Name)
  378. }
  379. return colSeq, cols, nil
  380. }
  381. func (db *mysql) GetTables() ([]*core.Table, error) {
  382. args := []interface{}{db.DbName}
  383. s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from " +
  384. "`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB')"
  385. rows, err := db.DB().Query(s, args...)
  386. if db.Logger != nil {
  387. db.Logger.Info("[sql]", s, args)
  388. }
  389. if err != nil {
  390. return nil, err
  391. }
  392. defer rows.Close()
  393. tables := make([]*core.Table, 0)
  394. for rows.Next() {
  395. table := core.NewEmptyTable()
  396. var name, engine, tableRows string
  397. var autoIncr *string
  398. err = rows.Scan(&name, &engine, &tableRows, &autoIncr)
  399. if err != nil {
  400. return nil, err
  401. }
  402. table.Name = name
  403. table.StoreEngine = engine
  404. tables = append(tables, table)
  405. }
  406. return tables, nil
  407. }
  408. func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
  409. args := []interface{}{db.DbName, tableName}
  410. s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
  411. rows, err := db.DB().Query(s, args...)
  412. if db.Logger != nil {
  413. db.Logger.Info("[sql]", s, args)
  414. }
  415. if err != nil {
  416. return nil, err
  417. }
  418. defer rows.Close()
  419. indexes := make(map[string]*core.Index, 0)
  420. for rows.Next() {
  421. var indexType int
  422. var indexName, colName, nonUnique string
  423. err = rows.Scan(&indexName, &nonUnique, &colName)
  424. if err != nil {
  425. return nil, err
  426. }
  427. if indexName == "PRIMARY" {
  428. continue
  429. }
  430. if "YES" == nonUnique || nonUnique == "1" {
  431. indexType = core.IndexType
  432. } else {
  433. indexType = core.UniqueType
  434. }
  435. colName = strings.Trim(colName, "` ")
  436. var isRegular bool
  437. if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
  438. indexName = indexName[5+len(tableName) : len(indexName)]
  439. isRegular = true
  440. }
  441. var index *core.Index
  442. var ok bool
  443. if index, ok = indexes[indexName]; !ok {
  444. index = new(core.Index)
  445. index.IsRegular = isRegular
  446. index.Type = indexType
  447. index.Name = indexName
  448. indexes[indexName] = index
  449. }
  450. index.AddColumn(colName)
  451. }
  452. return indexes, nil
  453. }
  454. func (db *mysql) Filters() []core.Filter {
  455. return []core.Filter{&core.IdFilter{}}
  456. }