session_delete.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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/xormplus/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.queryBytes(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. if session.isAutoClose {
  73. defer session.Close()
  74. }
  75. if err := session.statement.setRefValue(rValue(bean)); err != nil {
  76. return 0, err
  77. }
  78. var table = session.statement.RefTable
  79. // handle before delete processors
  80. for _, closure := range session.beforeClosures {
  81. closure(bean)
  82. }
  83. cleanupProcessorsClosures(&session.beforeClosures)
  84. if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
  85. processor.BeforeDelete()
  86. }
  87. condSQL, condArgs, err := session.statement.genConds(bean)
  88. if err != nil {
  89. return 0, err
  90. }
  91. if len(condSQL) == 0 && session.statement.LimitN == 0 {
  92. return 0, ErrNeedDeletedCond
  93. }
  94. var tableName = session.engine.Quote(session.statement.TableName())
  95. var deleteSQL string
  96. if len(condSQL) > 0 {
  97. deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
  98. } else {
  99. deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
  100. }
  101. var orderSQL string
  102. if len(session.statement.OrderStr) > 0 {
  103. orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
  104. }
  105. if session.statement.LimitN > 0 {
  106. orderSQL += fmt.Sprintf(" LIMIT %d", session.statement.LimitN)
  107. }
  108. if len(orderSQL) > 0 {
  109. switch session.engine.dialect.DBType() {
  110. case core.POSTGRES:
  111. inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
  112. if len(condSQL) > 0 {
  113. deleteSQL += " AND " + inSQL
  114. } else {
  115. deleteSQL += " WHERE " + inSQL
  116. }
  117. case core.SQLITE:
  118. inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
  119. if len(condSQL) > 0 {
  120. deleteSQL += " AND " + inSQL
  121. } else {
  122. deleteSQL += " WHERE " + inSQL
  123. }
  124. // TODO: how to handle delete limit on mssql?
  125. case core.MSSQL:
  126. return 0, ErrNotImplemented
  127. default:
  128. deleteSQL += orderSQL
  129. }
  130. }
  131. var realSQL string
  132. argsForCache := make([]interface{}, 0, len(condArgs)*2)
  133. if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
  134. realSQL = deleteSQL
  135. copy(argsForCache, condArgs)
  136. argsForCache = append(condArgs, argsForCache...)
  137. } else {
  138. // !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
  139. copy(argsForCache, condArgs)
  140. argsForCache = append(condArgs, argsForCache...)
  141. deletedColumn := table.DeletedColumn()
  142. realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
  143. session.engine.Quote(session.statement.TableName()),
  144. session.engine.Quote(deletedColumn.Name),
  145. condSQL)
  146. if len(orderSQL) > 0 {
  147. switch session.engine.dialect.DBType() {
  148. case core.POSTGRES:
  149. inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
  150. if len(condSQL) > 0 {
  151. realSQL += " AND " + inSQL
  152. } else {
  153. realSQL += " WHERE " + inSQL
  154. }
  155. case core.SQLITE:
  156. inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
  157. if len(condSQL) > 0 {
  158. realSQL += " AND " + inSQL
  159. } else {
  160. realSQL += " WHERE " + inSQL
  161. }
  162. // TODO: how to handle delete limit on mssql?
  163. case core.MSSQL:
  164. return 0, ErrNotImplemented
  165. default:
  166. realSQL += orderSQL
  167. }
  168. }
  169. // !oinume! Insert NowTime to the head of session.statement.Params
  170. condArgs = append(condArgs, "")
  171. paramsLen := len(condArgs)
  172. copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
  173. val, t := session.engine.NowTime2(deletedColumn.SQLType.Name)
  174. condArgs[0] = val
  175. var colName = deletedColumn.Name
  176. session.afterClosures = append(session.afterClosures, func(bean interface{}) {
  177. col := table.GetColumn(colName)
  178. setColumnTime(bean, col, t)
  179. })
  180. }
  181. if cacher := session.engine.getCacher2(session.statement.RefTable); cacher != nil && session.statement.UseCache {
  182. session.cacheDelete(deleteSQL, argsForCache...)
  183. }
  184. res, err := session.exec(realSQL, condArgs...)
  185. if err != nil {
  186. return 0, err
  187. }
  188. // handle after delete processors
  189. if session.isAutoCommit {
  190. for _, closure := range session.afterClosures {
  191. closure(bean)
  192. }
  193. if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
  194. processor.AfterDelete()
  195. }
  196. } else {
  197. lenAfterClosures := len(session.afterClosures)
  198. if lenAfterClosures > 0 {
  199. if value, has := session.afterDeleteBeans[bean]; has && value != nil {
  200. *value = append(*value, session.afterClosures...)
  201. } else {
  202. afterClosures := make([]func(interface{}), lenAfterClosures)
  203. copy(afterClosures, session.afterClosures)
  204. session.afterDeleteBeans[bean] = &afterClosures
  205. }
  206. } else {
  207. if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
  208. session.afterDeleteBeans[bean] = nil
  209. }
  210. }
  211. }
  212. cleanupProcessorsClosures(&session.afterClosures)
  213. // --
  214. return res.RowsAffected()
  215. }