session_schema.go 12 KB

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