session_schema.go 11 KB

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