dialect.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package migrator
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/go-xorm/xorm"
  6. )
  7. type Dialect interface {
  8. DriverName() string
  9. Quote(string) string
  10. AndStr() string
  11. AutoIncrStr() string
  12. OrStr() string
  13. EqStr() string
  14. ShowCreateNull() bool
  15. SqlType(col *Column) string
  16. SupportEngine() bool
  17. LikeStr() string
  18. Default(col *Column) string
  19. BooleanStr(bool) string
  20. DateTimeFunc(string) string
  21. CreateIndexSql(tableName string, index *Index) string
  22. CreateTableSql(table *Table) string
  23. AddColumnSql(tableName string, col *Column) string
  24. CopyTableData(sourceTable string, targetTable string, sourceCols []string, targetCols []string) string
  25. DropTable(tableName string) string
  26. DropIndexSql(tableName string, index *Index) string
  27. RenameTable(oldName string, newName string) string
  28. UpdateTableSql(tableName string, columns []*Column) string
  29. IndexCheckSql(tableName, indexName string) (string, []interface{})
  30. ColumnCheckSql(tableName, columnName string) (string, []interface{})
  31. ColString(*Column) string
  32. ColStringNoPk(*Column) string
  33. Limit(limit int64) string
  34. LimitOffset(limit int64, offset int64) string
  35. PreInsertId(table string, sess *xorm.Session) error
  36. PostInsertId(table string, sess *xorm.Session) error
  37. CleanDB() error
  38. NoOpSql() string
  39. IsUniqueConstraintViolation(err error) bool
  40. IsDeadlock(err error) bool
  41. }
  42. func NewDialect(engine *xorm.Engine) Dialect {
  43. name := engine.DriverName()
  44. switch name {
  45. case MYSQL:
  46. return NewMysqlDialect(engine)
  47. case SQLITE:
  48. return NewSqlite3Dialect(engine)
  49. case POSTGRES:
  50. return NewPostgresDialect(engine)
  51. }
  52. panic("Unsupported database type: " + name)
  53. }
  54. type BaseDialect struct {
  55. dialect Dialect
  56. engine *xorm.Engine
  57. driverName string
  58. }
  59. func (d *BaseDialect) DriverName() string {
  60. return d.driverName
  61. }
  62. func (b *BaseDialect) ShowCreateNull() bool {
  63. return true
  64. }
  65. func (b *BaseDialect) AndStr() string {
  66. return "AND"
  67. }
  68. func (b *BaseDialect) LikeStr() string {
  69. return "LIKE"
  70. }
  71. func (b *BaseDialect) OrStr() string {
  72. return "OR"
  73. }
  74. func (b *BaseDialect) EqStr() string {
  75. return "="
  76. }
  77. func (b *BaseDialect) Default(col *Column) string {
  78. return col.Default
  79. }
  80. func (db *BaseDialect) DateTimeFunc(value string) string {
  81. return value
  82. }
  83. func (b *BaseDialect) CreateTableSql(table *Table) string {
  84. sql := "CREATE TABLE IF NOT EXISTS "
  85. sql += b.dialect.Quote(table.Name) + " (\n"
  86. pkList := table.PrimaryKeys
  87. for _, col := range table.Columns {
  88. if col.IsPrimaryKey && len(pkList) == 1 {
  89. sql += col.String(b.dialect)
  90. } else {
  91. sql += col.StringNoPk(b.dialect)
  92. }
  93. sql = strings.TrimSpace(sql)
  94. sql += "\n, "
  95. }
  96. if len(pkList) > 1 {
  97. quotedCols := []string{}
  98. for _, col := range pkList {
  99. quotedCols = append(quotedCols, b.dialect.Quote(col))
  100. }
  101. sql += "PRIMARY KEY ( " + strings.Join(quotedCols, ",") + " ), "
  102. }
  103. sql = sql[:len(sql)-2] + ")"
  104. if b.dialect.SupportEngine() {
  105. sql += " ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci"
  106. }
  107. sql += ";"
  108. return sql
  109. }
  110. func (db *BaseDialect) AddColumnSql(tableName string, col *Column) string {
  111. return fmt.Sprintf("alter table %s ADD COLUMN %s", db.dialect.Quote(tableName), col.StringNoPk(db.dialect))
  112. }
  113. func (db *BaseDialect) CreateIndexSql(tableName string, index *Index) string {
  114. quote := db.dialect.Quote
  115. var unique string
  116. if index.Type == UniqueIndex {
  117. unique = " UNIQUE"
  118. }
  119. idxName := index.XName(tableName)
  120. quotedCols := []string{}
  121. for _, col := range index.Cols {
  122. quotedCols = append(quotedCols, db.dialect.Quote(col))
  123. }
  124. return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v);", unique, quote(idxName), quote(tableName), strings.Join(quotedCols, ","))
  125. }
  126. func (db *BaseDialect) QuoteColList(cols []string) string {
  127. var sourceColsSql = ""
  128. for _, col := range cols {
  129. sourceColsSql += db.dialect.Quote(col)
  130. sourceColsSql += "\n, "
  131. }
  132. return strings.TrimSuffix(sourceColsSql, "\n, ")
  133. }
  134. func (db *BaseDialect) CopyTableData(sourceTable string, targetTable string, sourceCols []string, targetCols []string) string {
  135. sourceColsSql := db.QuoteColList(sourceCols)
  136. targetColsSql := db.QuoteColList(targetCols)
  137. quote := db.dialect.Quote
  138. return fmt.Sprintf("INSERT INTO %s (%s) SELECT %s FROM %s", quote(targetTable), targetColsSql, sourceColsSql, quote(sourceTable))
  139. }
  140. func (db *BaseDialect) DropTable(tableName string) string {
  141. quote := db.dialect.Quote
  142. return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName))
  143. }
  144. func (db *BaseDialect) RenameTable(oldName string, newName string) string {
  145. quote := db.dialect.Quote
  146. return fmt.Sprintf("ALTER TABLE %s RENAME TO %s", quote(oldName), quote(newName))
  147. }
  148. func (db *BaseDialect) ColumnCheckSql(tableName, columnName string) (string, []interface{}) {
  149. return "", nil
  150. }
  151. func (db *BaseDialect) DropIndexSql(tableName string, index *Index) string {
  152. quote := db.dialect.Quote
  153. name := index.XName(tableName)
  154. return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
  155. }
  156. func (db *BaseDialect) UpdateTableSql(tableName string, columns []*Column) string {
  157. return "-- NOT REQUIRED"
  158. }
  159. func (db *BaseDialect) ColString(col *Column) string {
  160. sql := db.dialect.Quote(col.Name) + " "
  161. sql += db.dialect.SqlType(col) + " "
  162. if col.IsPrimaryKey {
  163. sql += "PRIMARY KEY "
  164. if col.IsAutoIncrement {
  165. sql += db.dialect.AutoIncrStr() + " "
  166. }
  167. }
  168. if db.dialect.ShowCreateNull() {
  169. if col.Nullable {
  170. sql += "NULL "
  171. } else {
  172. sql += "NOT NULL "
  173. }
  174. }
  175. if col.Default != "" {
  176. sql += "DEFAULT " + db.dialect.Default(col) + " "
  177. }
  178. return sql
  179. }
  180. func (db *BaseDialect) ColStringNoPk(col *Column) string {
  181. sql := db.dialect.Quote(col.Name) + " "
  182. sql += db.dialect.SqlType(col) + " "
  183. if db.dialect.ShowCreateNull() {
  184. if col.Nullable {
  185. sql += "NULL "
  186. } else {
  187. sql += "NOT NULL "
  188. }
  189. }
  190. if col.Default != "" {
  191. sql += "DEFAULT " + db.dialect.Default(col) + " "
  192. }
  193. return sql
  194. }
  195. func (db *BaseDialect) Limit(limit int64) string {
  196. return fmt.Sprintf(" LIMIT %d", limit)
  197. }
  198. func (db *BaseDialect) LimitOffset(limit int64, offset int64) string {
  199. return fmt.Sprintf(" LIMIT %d OFFSET %d", limit, offset)
  200. }
  201. func (db *BaseDialect) PreInsertId(table string, sess *xorm.Session) error {
  202. return nil
  203. }
  204. func (db *BaseDialect) PostInsertId(table string, sess *xorm.Session) error {
  205. return nil
  206. }
  207. func (db *BaseDialect) CleanDB() error {
  208. return nil
  209. }
  210. func (db *BaseDialect) NoOpSql() string {
  211. return "SELECT 0;"
  212. }