session_delete.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. "errors"
  7. "fmt"
  8. "strconv"
  9. "github.com/go-xorm/core"
  10. )
  11. func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error {
  12. if session.Statement.RefTable == nil ||
  13. session.Tx != nil {
  14. return ErrCacheFailed
  15. }
  16. for _, filter := range session.Engine.dialect.Filters() {
  17. sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
  18. }
  19. newsql := session.Statement.convertIDSQL(sqlStr)
  20. if newsql == "" {
  21. return ErrCacheFailed
  22. }
  23. cacher := session.Engine.getCacher2(session.Statement.RefTable)
  24. tableName := session.Statement.TableName()
  25. ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
  26. if err != nil {
  27. resultsSlice, err := session.query(newsql, args...)
  28. if err != nil {
  29. return err
  30. }
  31. ids = make([]core.PK, 0)
  32. if len(resultsSlice) > 0 {
  33. for _, data := range resultsSlice {
  34. var id int64
  35. var pk core.PK = make([]interface{}, 0)
  36. for _, col := range session.Statement.RefTable.PKColumns() {
  37. if v, ok := data[col.Name]; !ok {
  38. return errors.New("no id")
  39. } else if col.SQLType.IsText() {
  40. pk = append(pk, string(v))
  41. } else if col.SQLType.IsNumeric() {
  42. id, err = strconv.ParseInt(string(v), 10, 64)
  43. if err != nil {
  44. return err
  45. }
  46. pk = append(pk, id)
  47. } else {
  48. return errors.New("not supported primary key type")
  49. }
  50. }
  51. ids = append(ids, pk)
  52. }
  53. }
  54. } /*else {
  55. session.Engine.LogDebug("delete cache sql %v", newsql)
  56. cacher.DelIds(tableName, genSqlKey(newsql, args))
  57. }*/
  58. for _, id := range ids {
  59. session.Engine.logger.Debug("[cacheDelete] delete cache obj", tableName, id)
  60. sid, err := id.ToString()
  61. if err != nil {
  62. return err
  63. }
  64. cacher.DelBean(tableName, sid)
  65. }
  66. session.Engine.logger.Debug("[cacheDelete] clear cache sql", tableName)
  67. cacher.ClearIds(tableName)
  68. return nil
  69. }
  70. // Delete records, bean's non-empty fields are conditions
  71. func (session *Session) Delete(bean interface{}) (int64, error) {
  72. defer session.resetStatement()
  73. if session.IsAutoClose {
  74. defer session.Close()
  75. }
  76. if err := session.Statement.setRefValue(rValue(bean)); err != nil {
  77. return 0, err
  78. }
  79. var table = session.Statement.RefTable
  80. // handle before delete processors
  81. for _, closure := range session.beforeClosures {
  82. closure(bean)
  83. }
  84. cleanupProcessorsClosures(&session.beforeClosures)
  85. if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
  86. processor.BeforeDelete()
  87. }
  88. // --
  89. condSQL, condArgs, _ := session.Statement.genConds(bean)
  90. if len(condSQL) == 0 && session.Statement.LimitN == 0 {
  91. return 0, ErrNeedDeletedCond
  92. }
  93. var tableName = session.Engine.Quote(session.Statement.TableName())
  94. var deleteSQL string
  95. if len(condSQL) > 0 {
  96. deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
  97. } else {
  98. deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
  99. }
  100. var orderSQL string
  101. if len(session.Statement.OrderStr) > 0 {
  102. orderSQL += fmt.Sprintf(" ORDER BY %s", session.Statement.OrderStr)
  103. }
  104. if session.Statement.LimitN > 0 {
  105. orderSQL += fmt.Sprintf(" LIMIT %d", session.Statement.LimitN)
  106. }
  107. if len(orderSQL) > 0 {
  108. switch session.Engine.dialect.DBType() {
  109. case core.POSTGRES:
  110. inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
  111. if len(condSQL) > 0 {
  112. deleteSQL += " AND " + inSQL
  113. } else {
  114. deleteSQL += " WHERE " + inSQL
  115. }
  116. case core.SQLITE:
  117. inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
  118. if len(condSQL) > 0 {
  119. deleteSQL += " AND " + inSQL
  120. } else {
  121. deleteSQL += " WHERE " + inSQL
  122. }
  123. // TODO: how to handle delete limit on mssql?
  124. case core.MSSQL:
  125. return 0, ErrNotImplemented
  126. default:
  127. deleteSQL += orderSQL
  128. }
  129. }
  130. var realSQL string
  131. argsForCache := make([]interface{}, 0, len(condArgs)*2)
  132. if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
  133. realSQL = deleteSQL
  134. copy(argsForCache, condArgs)
  135. argsForCache = append(condArgs, argsForCache...)
  136. } else {
  137. // !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
  138. copy(argsForCache, condArgs)
  139. argsForCache = append(condArgs, argsForCache...)
  140. deletedColumn := table.DeletedColumn()
  141. realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
  142. session.Engine.Quote(session.Statement.TableName()),
  143. session.Engine.Quote(deletedColumn.Name),
  144. condSQL)
  145. if len(orderSQL) > 0 {
  146. switch session.Engine.dialect.DBType() {
  147. case core.POSTGRES:
  148. inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
  149. if len(condSQL) > 0 {
  150. realSQL += " AND " + inSQL
  151. } else {
  152. realSQL += " WHERE " + inSQL
  153. }
  154. case core.SQLITE:
  155. inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
  156. if len(condSQL) > 0 {
  157. realSQL += " AND " + inSQL
  158. } else {
  159. realSQL += " WHERE " + inSQL
  160. }
  161. // TODO: how to handle delete limit on mssql?
  162. case core.MSSQL:
  163. return 0, ErrNotImplemented
  164. default:
  165. realSQL += orderSQL
  166. }
  167. }
  168. // !oinume! Insert NowTime to the head of session.Statement.Params
  169. condArgs = append(condArgs, "")
  170. paramsLen := len(condArgs)
  171. copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
  172. val, t := session.Engine.NowTime2(deletedColumn.SQLType.Name)
  173. condArgs[0] = val
  174. var colName = deletedColumn.Name
  175. session.afterClosures = append(session.afterClosures, func(bean interface{}) {
  176. col := table.GetColumn(colName)
  177. setColumnTime(bean, col, t)
  178. })
  179. }
  180. if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache {
  181. session.cacheDelete(deleteSQL, argsForCache...)
  182. }
  183. res, err := session.exec(realSQL, condArgs...)
  184. if err != nil {
  185. return 0, err
  186. }
  187. // handle after delete processors
  188. if session.IsAutoCommit {
  189. for _, closure := range session.afterClosures {
  190. closure(bean)
  191. }
  192. if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
  193. processor.AfterDelete()
  194. }
  195. } else {
  196. lenAfterClosures := len(session.afterClosures)
  197. if lenAfterClosures > 0 {
  198. if value, has := session.afterDeleteBeans[bean]; has && value != nil {
  199. *value = append(*value, session.afterClosures...)
  200. } else {
  201. afterClosures := make([]func(interface{}), lenAfterClosures)
  202. copy(afterClosures, session.afterClosures)
  203. session.afterDeleteBeans[bean] = &afterClosures
  204. }
  205. } else {
  206. if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
  207. session.afterDeleteBeans[bean] = nil
  208. }
  209. }
  210. }
  211. cleanupProcessorsClosures(&session.afterClosures)
  212. // --
  213. return res.RowsAffected()
  214. }