session_delete.go 6.5 KB

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