session_schema.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // Copyright 2016 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. "database/sql"
  7. "errors"
  8. "fmt"
  9. "reflect"
  10. "strings"
  11. "github.com/xormplus/core"
  12. )
  13. // Ping test if database is ok
  14. func (session *Session) Ping() error {
  15. defer session.resetStatement()
  16. if session.isAutoClose {
  17. defer session.Close()
  18. }
  19. session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
  20. return session.DB().Ping()
  21. }
  22. // CreateTable create a table according a bean
  23. func (session *Session) CreateTable(bean interface{}) error {
  24. if session.isAutoClose {
  25. defer session.Close()
  26. }
  27. return session.createTable(bean)
  28. }
  29. func (session *Session) createTable(bean interface{}) error {
  30. defer session.resetStatement()
  31. v := rValue(bean)
  32. if err := session.statement.setRefValue(v); err != nil {
  33. return err
  34. }
  35. sqlStr := session.statement.genCreateTableSQL()
  36. _, err := session.exec(sqlStr)
  37. return err
  38. }
  39. // CreateIndexes create indexes
  40. func (session *Session) CreateIndexes(bean interface{}) error {
  41. if session.isAutoClose {
  42. defer session.Close()
  43. }
  44. return session.createIndexes(bean)
  45. }
  46. func (session *Session) createIndexes(bean interface{}) error {
  47. defer session.resetStatement()
  48. v := rValue(bean)
  49. if err := session.statement.setRefValue(v); err != nil {
  50. return err
  51. }
  52. sqls := session.statement.genIndexSQL()
  53. for _, sqlStr := range sqls {
  54. _, err := session.exec(sqlStr)
  55. if err != nil {
  56. return err
  57. }
  58. }
  59. return nil
  60. }
  61. // CreateUniques create uniques
  62. func (session *Session) CreateUniques(bean interface{}) error {
  63. if session.isAutoClose {
  64. defer session.Close()
  65. }
  66. return session.createUniques(bean)
  67. }
  68. func (session *Session) createUniques(bean interface{}) error {
  69. defer session.resetStatement()
  70. v := rValue(bean)
  71. if err := session.statement.setRefValue(v); err != nil {
  72. return err
  73. }
  74. sqls := session.statement.genUniqueSQL()
  75. for _, sqlStr := range sqls {
  76. _, err := session.exec(sqlStr)
  77. if err != nil {
  78. return err
  79. }
  80. }
  81. return nil
  82. }
  83. // DropIndexes drop indexes
  84. func (session *Session) DropIndexes(bean interface{}) error {
  85. if session.isAutoClose {
  86. defer session.Close()
  87. }
  88. return session.dropIndexes(bean)
  89. }
  90. func (session *Session) dropIndexes(bean interface{}) error {
  91. defer session.resetStatement()
  92. v := rValue(bean)
  93. if err := session.statement.setRefValue(v); err != nil {
  94. return err
  95. }
  96. sqls := session.statement.genDelIndexSQL()
  97. for _, sqlStr := range sqls {
  98. _, err := session.exec(sqlStr)
  99. if err != nil {
  100. return err
  101. }
  102. }
  103. return nil
  104. }
  105. // DropTable drop table will drop table if exist, if drop failed, it will return error
  106. func (session *Session) DropTable(beanOrTableName interface{}) error {
  107. if session.isAutoClose {
  108. defer session.Close()
  109. }
  110. return session.dropTable(beanOrTableName)
  111. }
  112. func (session *Session) dropTable(beanOrTableName interface{}) error {
  113. defer session.resetStatement()
  114. tableName, err := session.engine.tableName(beanOrTableName)
  115. if err != nil {
  116. return err
  117. }
  118. var needDrop = true
  119. if !session.engine.dialect.SupportDropIfExists() {
  120. sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
  121. results, err := session.query(sqlStr, args...)
  122. if err != nil {
  123. return err
  124. }
  125. needDrop = len(results) > 0
  126. }
  127. if needDrop {
  128. sqlStr := session.engine.Dialect().DropTableSql(tableName)
  129. _, err = session.exec(sqlStr)
  130. return err
  131. }
  132. return nil
  133. }
  134. // IsTableExist if a table is exist
  135. func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
  136. if session.isAutoClose {
  137. defer session.Close()
  138. }
  139. tableName, err := session.engine.tableName(beanOrTableName)
  140. if err != nil {
  141. return false, err
  142. }
  143. return session.isTableExist(tableName)
  144. }
  145. func (session *Session) isTableExist(tableName string) (bool, error) {
  146. defer session.resetStatement()
  147. sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
  148. results, err := session.query(sqlStr, args...)
  149. return len(results) > 0, err
  150. }
  151. // IsTableEmpty if table have any records
  152. func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
  153. v := rValue(bean)
  154. t := v.Type()
  155. if t.Kind() == reflect.String {
  156. if session.isAutoClose {
  157. defer session.Close()
  158. }
  159. return session.isTableEmpty(bean.(string))
  160. } else if t.Kind() == reflect.Struct {
  161. rows, err := session.Count(bean)
  162. return rows == 0, err
  163. }
  164. return false, errors.New("bean should be a struct or struct's point")
  165. }
  166. func (session *Session) isTableEmpty(tableName string) (bool, error) {
  167. defer session.resetStatement()
  168. var total int64
  169. sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(tableName))
  170. err := session.DB().QueryRow(sqlStr).Scan(&total)
  171. session.saveLastSQL(sqlStr)
  172. if err != nil {
  173. if err == sql.ErrNoRows {
  174. err = nil
  175. }
  176. return true, err
  177. }
  178. return total == 0, nil
  179. }
  180. // find if index is exist according cols
  181. func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
  182. defer session.resetStatement()
  183. indexes, err := session.engine.dialect.GetIndexes(tableName)
  184. if err != nil {
  185. return false, err
  186. }
  187. for _, index := range indexes {
  188. if sliceEq(index.Cols, cols) {
  189. if unique {
  190. return index.Type == core.UniqueType, nil
  191. }
  192. return index.Type == core.IndexType, nil
  193. }
  194. }
  195. return false, nil
  196. }
  197. func (session *Session) addColumn(colName string) error {
  198. defer session.resetStatement()
  199. col := session.statement.RefTable.GetColumn(colName)
  200. sql, args := session.statement.genAddColumnStr(col)
  201. _, err := session.exec(sql, args...)
  202. return err
  203. }
  204. func (session *Session) addIndex(tableName, idxName string) error {
  205. defer session.resetStatement()
  206. index := session.statement.RefTable.Indexes[idxName]
  207. sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
  208. _, err := session.exec(sqlStr)
  209. return err
  210. }
  211. func (session *Session) addUnique(tableName, uqeName string) error {
  212. defer session.resetStatement()
  213. index := session.statement.RefTable.Indexes[uqeName]
  214. sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
  215. _, err := session.exec(sqlStr)
  216. return err
  217. }
  218. // Sync2 synchronize structs to database tables
  219. func (session *Session) Sync2(beans ...interface{}) error {
  220. engine := session.engine
  221. if session.isAutoClose {
  222. session.isAutoClose = false
  223. defer session.Close()
  224. }
  225. tables, err := engine.DBMetas()
  226. if err != nil {
  227. return err
  228. }
  229. var structTables []*core.Table
  230. for _, bean := range beans {
  231. v := rValue(bean)
  232. table, err := engine.mapType(v)
  233. if err != nil {
  234. return err
  235. }
  236. structTables = append(structTables, table)
  237. var tbName = session.tbNameNoSchema(table)
  238. var oriTable *core.Table
  239. for _, tb := range tables {
  240. if strings.EqualFold(tb.Name, tbName) {
  241. oriTable = tb
  242. break
  243. }
  244. }
  245. if oriTable == nil {
  246. err = session.StoreEngine(session.statement.StoreEngine).createTable(bean)
  247. if err != nil {
  248. return err
  249. }
  250. err = session.createUniques(bean)
  251. if err != nil {
  252. return err
  253. }
  254. err = session.createIndexes(bean)
  255. if err != nil {
  256. return err
  257. }
  258. } else {
  259. for _, col := range table.Columns() {
  260. var oriCol *core.Column
  261. for _, col2 := range oriTable.Columns() {
  262. if strings.EqualFold(col.Name, col2.Name) {
  263. oriCol = col2
  264. break
  265. }
  266. }
  267. if oriCol != nil {
  268. expectedType := engine.dialect.SqlType(col)
  269. curType := engine.dialect.SqlType(oriCol)
  270. if expectedType != curType {
  271. if expectedType == core.Text &&
  272. strings.HasPrefix(curType, core.Varchar) {
  273. // currently only support mysql & postgres
  274. if engine.dialect.DBType() == core.MYSQL ||
  275. engine.dialect.DBType() == core.POSTGRES {
  276. engine.logger.Infof("Table %s column %s change type from %s to %s\n",
  277. tbName, col.Name, curType, expectedType)
  278. _, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
  279. } else {
  280. engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
  281. tbName, col.Name, curType, expectedType)
  282. }
  283. } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
  284. if engine.dialect.DBType() == core.MYSQL {
  285. if oriCol.Length < col.Length {
  286. engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
  287. tbName, col.Name, oriCol.Length, col.Length)
  288. _, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
  289. }
  290. }
  291. } else {
  292. if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
  293. engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
  294. tbName, col.Name, curType, expectedType)
  295. }
  296. }
  297. } else if expectedType == core.Varchar {
  298. if engine.dialect.DBType() == core.MYSQL {
  299. if oriCol.Length < col.Length {
  300. engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
  301. tbName, col.Name, oriCol.Length, col.Length)
  302. _, err = session.exec(engine.dialect.ModifyColumnSql(table.Name, col))
  303. }
  304. }
  305. }
  306. if col.Default != oriCol.Default {
  307. engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s",
  308. tbName, col.Name, oriCol.Default, col.Default)
  309. }
  310. if col.Nullable != oriCol.Nullable {
  311. engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v",
  312. tbName, col.Name, oriCol.Nullable, col.Nullable)
  313. }
  314. } else {
  315. session.statement.RefTable = table
  316. session.statement.tableName = tbName
  317. err = session.addColumn(col.Name)
  318. }
  319. if err != nil {
  320. return err
  321. }
  322. }
  323. var foundIndexNames = make(map[string]bool)
  324. var addedNames = make(map[string]*core.Index)
  325. for name, index := range table.Indexes {
  326. var oriIndex *core.Index
  327. for name2, index2 := range oriTable.Indexes {
  328. if index.Equal(index2) {
  329. oriIndex = index2
  330. foundIndexNames[name2] = true
  331. break
  332. }
  333. }
  334. if oriIndex != nil {
  335. if oriIndex.Type != index.Type {
  336. sql := engine.dialect.DropIndexSql(tbName, oriIndex)
  337. _, err = session.exec(sql)
  338. if err != nil {
  339. return err
  340. }
  341. oriIndex = nil
  342. }
  343. }
  344. if oriIndex == nil {
  345. addedNames[name] = index
  346. }
  347. }
  348. for name2, index2 := range oriTable.Indexes {
  349. if _, ok := foundIndexNames[name2]; !ok {
  350. sql := engine.dialect.DropIndexSql(tbName, index2)
  351. _, err = session.exec(sql)
  352. if err != nil {
  353. return err
  354. }
  355. }
  356. }
  357. for name, index := range addedNames {
  358. if index.Type == core.UniqueType {
  359. session.statement.RefTable = table
  360. session.statement.tableName = tbName
  361. err = session.addUnique(tbName, name)
  362. } else if index.Type == core.IndexType {
  363. session.statement.RefTable = table
  364. session.statement.tableName = tbName
  365. err = session.addIndex(tbName, name)
  366. }
  367. if err != nil {
  368. return err
  369. }
  370. }
  371. }
  372. }
  373. for _, table := range tables {
  374. var oriTable *core.Table
  375. for _, structTable := range structTables {
  376. if strings.EqualFold(table.Name, session.tbNameNoSchema(structTable)) {
  377. oriTable = structTable
  378. break
  379. }
  380. }
  381. if oriTable == nil {
  382. //engine.LogWarnf("Table %s has no struct to mapping it", table.Name)
  383. continue
  384. }
  385. for _, colName := range table.ColumnsSeq() {
  386. if oriTable.GetColumn(colName) == nil {
  387. engine.logger.Warnf("Table %s has column %s but struct has not related field", table.Name, colName)
  388. }
  389. }
  390. }
  391. return nil
  392. }