dialect.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright 2019 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 core
  5. import (
  6. "fmt"
  7. "strings"
  8. "time"
  9. )
  10. type DbType string
  11. type Uri struct {
  12. DbType DbType
  13. Proto string
  14. Host string
  15. Port string
  16. DbName string
  17. User string
  18. Passwd string
  19. Charset string
  20. Laddr string
  21. Raddr string
  22. Timeout time.Duration
  23. Schema string
  24. }
  25. // a dialect is a driver's wrapper
  26. type Dialect interface {
  27. SetLogger(logger ILogger)
  28. Init(*DB, *Uri, string, string) error
  29. URI() *Uri
  30. DB() *DB
  31. DBType() DbType
  32. SqlType(*Column) string
  33. FormatBytes(b []byte) string
  34. DriverName() string
  35. DataSourceName() string
  36. IsReserved(string) bool
  37. Quote(string) string
  38. // Deprecated: use Quote(string) string instead
  39. QuoteStr() string
  40. AndStr() string
  41. OrStr() string
  42. EqStr() string
  43. RollBackStr() string
  44. AutoIncrStr() string
  45. SupportInsertMany() bool
  46. SupportEngine() bool
  47. SupportCharset() bool
  48. SupportDropIfExists() bool
  49. IndexOnTable() bool
  50. ShowCreateNull() bool
  51. IndexCheckSql(tableName, idxName string) (string, []interface{})
  52. TableCheckSql(tableName string) (string, []interface{})
  53. IsColumnExist(tableName string, colName string) (bool, error)
  54. CreateTableSql(table *Table, tableName, storeEngine, charset string) string
  55. DropTableSql(tableName string) string
  56. CreateIndexSql(tableName string, index *Index) string
  57. DropIndexSql(tableName string, index *Index) string
  58. ModifyColumnSql(tableName string, col *Column) string
  59. ForUpdateSql(query string) string
  60. // CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error
  61. // MustDropTable(tableName string) error
  62. GetColumns(tableName string) ([]string, map[string]*Column, error)
  63. GetTables() ([]*Table, error)
  64. GetIndexes(tableName string) (map[string]*Index, error)
  65. Filters() []Filter
  66. SetParams(params map[string]string)
  67. }
  68. func OpenDialect(dialect Dialect) (*DB, error) {
  69. return Open(dialect.DriverName(), dialect.DataSourceName())
  70. }
  71. // Base represents a basic dialect and all real dialects could embed this struct
  72. type Base struct {
  73. db *DB
  74. dialect Dialect
  75. driverName string
  76. dataSourceName string
  77. logger ILogger
  78. *Uri
  79. }
  80. func (b *Base) DB() *DB {
  81. return b.db
  82. }
  83. func (b *Base) SetLogger(logger ILogger) {
  84. b.logger = logger
  85. }
  86. func (b *Base) Init(db *DB, dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
  87. b.db, b.dialect, b.Uri = db, dialect, uri
  88. b.driverName, b.dataSourceName = drivername, dataSourceName
  89. return nil
  90. }
  91. func (b *Base) URI() *Uri {
  92. return b.Uri
  93. }
  94. func (b *Base) DBType() DbType {
  95. return b.Uri.DbType
  96. }
  97. func (b *Base) FormatBytes(bs []byte) string {
  98. return fmt.Sprintf("0x%x", bs)
  99. }
  100. func (b *Base) DriverName() string {
  101. return b.driverName
  102. }
  103. func (b *Base) ShowCreateNull() bool {
  104. return true
  105. }
  106. func (b *Base) DataSourceName() string {
  107. return b.dataSourceName
  108. }
  109. func (b *Base) AndStr() string {
  110. return "AND"
  111. }
  112. func (b *Base) OrStr() string {
  113. return "OR"
  114. }
  115. func (b *Base) EqStr() string {
  116. return "="
  117. }
  118. func (db *Base) RollBackStr() string {
  119. return "ROLL BACK"
  120. }
  121. func (db *Base) SupportDropIfExists() bool {
  122. return true
  123. }
  124. func (db *Base) DropTableSql(tableName string) string {
  125. quote := db.dialect.Quote
  126. return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName))
  127. }
  128. func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {
  129. db.LogSQL(query, args)
  130. rows, err := db.DB().Query(query, args...)
  131. if err != nil {
  132. return false, err
  133. }
  134. defer rows.Close()
  135. if rows.Next() {
  136. return true, nil
  137. }
  138. return false, nil
  139. }
  140. func (db *Base) IsColumnExist(tableName, colName string) (bool, error) {
  141. query := fmt.Sprintf(
  142. "SELECT %v FROM %v.%v WHERE %v = ? AND %v = ? AND %v = ?",
  143. db.dialect.Quote("COLUMN_NAME"),
  144. db.dialect.Quote("INFORMATION_SCHEMA"),
  145. db.dialect.Quote("COLUMNS"),
  146. db.dialect.Quote("TABLE_SCHEMA"),
  147. db.dialect.Quote("TABLE_NAME"),
  148. db.dialect.Quote("COLUMN_NAME"),
  149. )
  150. return db.HasRecords(query, db.DbName, tableName, colName)
  151. }
  152. /*
  153. func (db *Base) CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error {
  154. sql, args := db.dialect.TableCheckSql(tableName)
  155. rows, err := db.DB().Query(sql, args...)
  156. if db.Logger != nil {
  157. db.Logger.Info("[sql]", sql, args)
  158. }
  159. if err != nil {
  160. return err
  161. }
  162. defer rows.Close()
  163. if rows.Next() {
  164. return nil
  165. }
  166. sql = db.dialect.CreateTableSql(table, tableName, storeEngine, charset)
  167. _, err = db.DB().Exec(sql)
  168. if db.Logger != nil {
  169. db.Logger.Info("[sql]", sql)
  170. }
  171. return err
  172. }*/
  173. func (db *Base) CreateIndexSql(tableName string, index *Index) string {
  174. quote := db.dialect.Quote
  175. var unique string
  176. var idxName string
  177. if index.Type == UniqueType {
  178. unique = " UNIQUE"
  179. }
  180. idxName = index.XName(tableName)
  181. return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v)", unique,
  182. quote(idxName), quote(tableName),
  183. quote(strings.Join(index.Cols, quote(","))))
  184. }
  185. func (db *Base) DropIndexSql(tableName string, index *Index) string {
  186. quote := db.dialect.Quote
  187. var name string
  188. if index.IsRegular {
  189. name = index.XName(tableName)
  190. } else {
  191. name = index.Name
  192. }
  193. return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
  194. }
  195. func (db *Base) ModifyColumnSql(tableName string, col *Column) string {
  196. return fmt.Sprintf("alter table %s MODIFY COLUMN %s", tableName, col.StringNoPk(db.dialect))
  197. }
  198. func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset string) string {
  199. var sql string
  200. sql = "CREATE TABLE IF NOT EXISTS "
  201. if tableName == "" {
  202. tableName = table.Name
  203. }
  204. sql += b.dialect.Quote(tableName)
  205. sql += " ("
  206. if len(table.ColumnsSeq()) > 0 {
  207. pkList := table.PrimaryKeys
  208. for _, colName := range table.ColumnsSeq() {
  209. col := table.GetColumn(colName)
  210. if col.IsPrimaryKey && len(pkList) == 1 {
  211. sql += col.String(b.dialect)
  212. } else {
  213. sql += col.StringNoPk(b.dialect)
  214. }
  215. sql = strings.TrimSpace(sql)
  216. if b.DriverName() == MYSQL && len(col.Comment) > 0 {
  217. sql += " COMMENT '" + col.Comment + "'"
  218. }
  219. sql += ", "
  220. }
  221. if len(pkList) > 1 {
  222. sql += "PRIMARY KEY ( "
  223. sql += b.dialect.Quote(strings.Join(pkList, b.dialect.Quote(",")))
  224. sql += " ), "
  225. }
  226. sql = sql[:len(sql)-2]
  227. }
  228. sql += ")"
  229. if b.dialect.SupportEngine() && storeEngine != "" {
  230. sql += " ENGINE=" + storeEngine
  231. }
  232. if b.dialect.SupportCharset() {
  233. if len(charset) == 0 {
  234. charset = b.dialect.URI().Charset
  235. }
  236. if len(charset) > 0 {
  237. sql += " DEFAULT CHARSET " + charset
  238. }
  239. }
  240. return sql
  241. }
  242. func (b *Base) ForUpdateSql(query string) string {
  243. return query + " FOR UPDATE"
  244. }
  245. func (b *Base) LogSQL(sql string, args []interface{}) {
  246. if b.logger != nil && b.logger.IsShowSQL() {
  247. if len(args) > 0 {
  248. b.logger.Infof("[SQL] %v %v", sql, args)
  249. } else {
  250. b.logger.Infof("[SQL] %v", sql)
  251. }
  252. }
  253. }
  254. func (b *Base) SetParams(params map[string]string) {
  255. }
  256. var (
  257. dialects = map[string]func() Dialect{}
  258. )
  259. // RegisterDialect register database dialect
  260. func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
  261. if dialectFunc == nil {
  262. panic("core: Register dialect is nil")
  263. }
  264. dialects[strings.ToLower(string(dbName))] = dialectFunc // !nashtsai! allow override dialect
  265. }
  266. // QueryDialect query if registered database dialect
  267. func QueryDialect(dbName DbType) Dialect {
  268. if d, ok := dialects[strings.ToLower(string(dbName))]; ok {
  269. return d()
  270. }
  271. return nil
  272. }